xref: /optee_os/core/drivers/stm32mp15_huk.c (revision 7cb0cbbab87cc1bc03786c900ed84c09060921e6)
17e203c67SJorge Ramirez-Ortiz // SPDX-License-Identifier: BSD-2-Clause
27e203c67SJorge Ramirez-Ortiz /*
37e203c67SJorge Ramirez-Ortiz  * Copyright (c) 2022, Linaro Limited
47e203c67SJorge Ramirez-Ortiz  * Copyright (c) 2022, Foundries.io Limited
57e203c67SJorge Ramirez-Ortiz  */
67e203c67SJorge Ramirez-Ortiz 
77e203c67SJorge Ramirez-Ortiz #include <assert.h>
87e203c67SJorge Ramirez-Ortiz #include <config.h>
97e203c67SJorge Ramirez-Ortiz #include <crypto/crypto.h>
107e203c67SJorge Ramirez-Ortiz #include <drivers/stm32_bsec.h>
117e203c67SJorge Ramirez-Ortiz #include <kernel/tee_common_otp.h>
127e203c67SJorge Ramirez-Ortiz #include <mempool.h>
137e203c67SJorge Ramirez-Ortiz #include <platform_config.h>
147e203c67SJorge Ramirez-Ortiz #include <stm32_util.h>
157e203c67SJorge Ramirez-Ortiz #include <string.h>
167e203c67SJorge Ramirez-Ortiz #include <string_ext.h>
177e203c67SJorge Ramirez-Ortiz 
187e203c67SJorge Ramirez-Ortiz static bool stm32mp15_huk_init;
197e203c67SJorge Ramirez-Ortiz 
207e203c67SJorge Ramirez-Ortiz static TEE_Result stm32mp15_read_uid(uint32_t *uid)
217e203c67SJorge Ramirez-Ortiz {
227e203c67SJorge Ramirez-Ortiz 	uint32_t *q = uid;
237e203c67SJorge Ramirez-Ortiz 
247e203c67SJorge Ramirez-Ortiz 	/*
257e203c67SJorge Ramirez-Ortiz 	 * Shadow memory for UID words might not be locked: to guarante that
267e203c67SJorge Ramirez-Ortiz 	 * the final values are read we must lock them.
277e203c67SJorge Ramirez-Ortiz 	 */
287e203c67SJorge Ramirez-Ortiz 	if (stm32_bsec_set_sw_lock(UID0_OTP) ||
297e203c67SJorge Ramirez-Ortiz 	    stm32_bsec_shadow_read_otp(q++, UID0_OTP))
307e203c67SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
317e203c67SJorge Ramirez-Ortiz 
327e203c67SJorge Ramirez-Ortiz 	if (stm32_bsec_set_sw_lock(UID1_OTP) ||
337e203c67SJorge Ramirez-Ortiz 	    stm32_bsec_shadow_read_otp(q++, UID1_OTP))
347e203c67SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
357e203c67SJorge Ramirez-Ortiz 
367e203c67SJorge Ramirez-Ortiz 	if (stm32_bsec_set_sw_lock(UID2_OTP) ||
377e203c67SJorge Ramirez-Ortiz 	    stm32_bsec_shadow_read_otp(q++, UID2_OTP))
387e203c67SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
397e203c67SJorge Ramirez-Ortiz 
407e203c67SJorge Ramirez-Ortiz 	return TEE_SUCCESS;
417e203c67SJorge Ramirez-Ortiz }
427e203c67SJorge Ramirez-Ortiz 
437e203c67SJorge Ramirez-Ortiz static TEE_Result stm32mp15_read_otp(uint32_t otp, uint32_t *key, bool *locked)
447e203c67SJorge Ramirez-Ortiz {
457e203c67SJorge Ramirez-Ortiz 	bool tmp = true;
46*7cb0cbbaSGatien Chevallier 	uint32_t state = 0;
477e203c67SJorge Ramirez-Ortiz 
48*7cb0cbbaSGatien Chevallier 	if (stm32_bsec_get_state(&state))
49*7cb0cbbaSGatien Chevallier 		panic();
50*7cb0cbbaSGatien Chevallier 
51*7cb0cbbaSGatien Chevallier 	if (state != BSEC_STATE_SEC_CLOSED) {
527e203c67SJorge Ramirez-Ortiz 		/*
537e203c67SJorge Ramirez-Ortiz 		 * When the device is not closed, the shadow memory for these
547e203c67SJorge Ramirez-Ortiz 		 * words might not be locked: check and report them
557e203c67SJorge Ramirez-Ortiz 		 */
567e203c67SJorge Ramirez-Ortiz 		if (stm32_bsec_read_permanent_lock(otp, &tmp))
577e203c67SJorge Ramirez-Ortiz 			return TEE_ERROR_GENERIC;
587e203c67SJorge Ramirez-Ortiz 
597e203c67SJorge Ramirez-Ortiz 		if (tmp && stm32_bsec_read_sw_lock(otp, &tmp))
607e203c67SJorge Ramirez-Ortiz 			return TEE_ERROR_GENERIC;
617e203c67SJorge Ramirez-Ortiz 	}
627e203c67SJorge Ramirez-Ortiz 
637e203c67SJorge Ramirez-Ortiz 	if (stm32_bsec_shadow_read_otp(key, otp))
647e203c67SJorge Ramirez-Ortiz 		return TEE_ERROR_GENERIC;
657e203c67SJorge Ramirez-Ortiz 
667e203c67SJorge Ramirez-Ortiz 	*locked = *locked && tmp;
677e203c67SJorge Ramirez-Ortiz 
687e203c67SJorge Ramirez-Ortiz 	return TEE_SUCCESS;
697e203c67SJorge Ramirez-Ortiz }
707e203c67SJorge Ramirez-Ortiz 
717e203c67SJorge Ramirez-Ortiz /*
727e203c67SJorge Ramirez-Ortiz  *  AES-GCM: nonce must be unique per message and key.
737e203c67SJorge Ramirez-Ortiz  *
747e203c67SJorge Ramirez-Ortiz  *  This function always uses the same key - once its locked - with the same
757e203c67SJorge Ramirez-Ortiz  *  unique message hence the nonce can be any constant.
767e203c67SJorge Ramirez-Ortiz  */
777e203c67SJorge Ramirez-Ortiz static TEE_Result aes_gcm_encrypt_uid(uint8_t *key, size_t key_len,
787e203c67SJorge Ramirez-Ortiz 				      uint8_t *out, size_t *out_len)
797e203c67SJorge Ramirez-Ortiz {
807e203c67SJorge Ramirez-Ortiz 	TEE_Result ret = TEE_ERROR_GENERIC;
817e203c67SJorge Ramirez-Ortiz 	const uint8_t nonce[12] = { 0x55 };
827e203c67SJorge Ramirez-Ortiz 	uint32_t uid[4] = { 0 };
837e203c67SJorge Ramirez-Ortiz 	uint8_t tag[16] = { 0 };
847e203c67SJorge Ramirez-Ortiz 	size_t nonce_len = sizeof(nonce);
857e203c67SJorge Ramirez-Ortiz 	size_t tag_len = sizeof(tag);
867e203c67SJorge Ramirez-Ortiz 	size_t uid_len = sizeof(uid);
877e203c67SJorge Ramirez-Ortiz 	void *ctx = NULL;
887e203c67SJorge Ramirez-Ortiz 
897e203c67SJorge Ramirez-Ortiz 	ret = stm32mp15_read_uid(uid);
907e203c67SJorge Ramirez-Ortiz 	if (ret)
917e203c67SJorge Ramirez-Ortiz 		goto out;
927e203c67SJorge Ramirez-Ortiz 
937e203c67SJorge Ramirez-Ortiz 	ret = crypto_authenc_alloc_ctx(&ctx, TEE_ALG_AES_GCM);
947e203c67SJorge Ramirez-Ortiz 	if (ret)
957e203c67SJorge Ramirez-Ortiz 		goto out;
967e203c67SJorge Ramirez-Ortiz 
977e203c67SJorge Ramirez-Ortiz 	ret = crypto_authenc_init(ctx, TEE_MODE_ENCRYPT, key, key_len, nonce,
987e203c67SJorge Ramirez-Ortiz 				  nonce_len, TEE_AES_BLOCK_SIZE, 0, uid_len);
997e203c67SJorge Ramirez-Ortiz 	if (ret)
1007e203c67SJorge Ramirez-Ortiz 		goto out_free_ctx;
1017e203c67SJorge Ramirez-Ortiz 
1027e203c67SJorge Ramirez-Ortiz 	ret = crypto_authenc_enc_final(ctx, (uint8_t *)uid, sizeof(uid),
1037e203c67SJorge Ramirez-Ortiz 				       out, out_len, tag, &tag_len);
1047e203c67SJorge Ramirez-Ortiz 	if (ret)
1057e203c67SJorge Ramirez-Ortiz 		goto out_free_ctx;
1067e203c67SJorge Ramirez-Ortiz 
1077e203c67SJorge Ramirez-Ortiz 	crypto_authenc_final(ctx);
1087e203c67SJorge Ramirez-Ortiz out_free_ctx:
1097e203c67SJorge Ramirez-Ortiz 	crypto_authenc_free_ctx(ctx);
1107e203c67SJorge Ramirez-Ortiz out:
1117e203c67SJorge Ramirez-Ortiz 	if (ret)
1127e203c67SJorge Ramirez-Ortiz 		memzero_explicit(out, *out_len);
1137e203c67SJorge Ramirez-Ortiz 
1147e203c67SJorge Ramirez-Ortiz 	return ret;
1157e203c67SJorge Ramirez-Ortiz }
1167e203c67SJorge Ramirez-Ortiz 
1177e203c67SJorge Ramirez-Ortiz TEE_Result tee_otp_get_hw_unique_key(struct tee_hw_unique_key *hwkey)
1187e203c67SJorge Ramirez-Ortiz {
1197e203c67SJorge Ramirez-Ortiz 	uint32_t otp_key[4] = { 0 };
1207e203c67SJorge Ramirez-Ortiz 	size_t len = sizeof(otp_key);
1217e203c67SJorge Ramirez-Ortiz 	TEE_Result ret = TEE_SUCCESS;
1227e203c67SJorge Ramirez-Ortiz 	uint32_t *key = otp_key;
1237e203c67SJorge Ramirez-Ortiz 	bool lock = true;
1247e203c67SJorge Ramirez-Ortiz 
1257e203c67SJorge Ramirez-Ortiz 	static_assert(CFG_STM32MP15_HUK_BSEC_KEY_0 < STM32MP1_OTP_MAX_ID);
1267e203c67SJorge Ramirez-Ortiz 	static_assert(CFG_STM32MP15_HUK_BSEC_KEY_1 < STM32MP1_OTP_MAX_ID);
1277e203c67SJorge Ramirez-Ortiz 	static_assert(CFG_STM32MP15_HUK_BSEC_KEY_2 < STM32MP1_OTP_MAX_ID);
1287e203c67SJorge Ramirez-Ortiz 	static_assert(CFG_STM32MP15_HUK_BSEC_KEY_3 < STM32MP1_OTP_MAX_ID);
1297e203c67SJorge Ramirez-Ortiz 
1307e203c67SJorge Ramirez-Ortiz 	ret = stm32mp15_read_otp(CFG_STM32MP15_HUK_BSEC_KEY_0, key++, &lock);
1317e203c67SJorge Ramirez-Ortiz 	if (ret)
1327e203c67SJorge Ramirez-Ortiz 		goto out;
1337e203c67SJorge Ramirez-Ortiz 
1347e203c67SJorge Ramirez-Ortiz 	ret = stm32mp15_read_otp(CFG_STM32MP15_HUK_BSEC_KEY_1, key++, &lock);
1357e203c67SJorge Ramirez-Ortiz 	if (ret)
1367e203c67SJorge Ramirez-Ortiz 		goto out;
1377e203c67SJorge Ramirez-Ortiz 
1387e203c67SJorge Ramirez-Ortiz 	ret = stm32mp15_read_otp(CFG_STM32MP15_HUK_BSEC_KEY_2, key++, &lock);
1397e203c67SJorge Ramirez-Ortiz 	if (ret)
1407e203c67SJorge Ramirez-Ortiz 		goto out;
1417e203c67SJorge Ramirez-Ortiz 
1427e203c67SJorge Ramirez-Ortiz 	ret = stm32mp15_read_otp(CFG_STM32MP15_HUK_BSEC_KEY_3, key++, &lock);
1437e203c67SJorge Ramirez-Ortiz 	if (ret)
1447e203c67SJorge Ramirez-Ortiz 		goto out;
1457e203c67SJorge Ramirez-Ortiz 
146a833cb74SEtienne Carriere 	if (IS_ENABLED(CFG_STM32MP15_HUK_BSEC_KEY)) {
147a833cb74SEtienne Carriere 		static_assert(sizeof(otp_key) == HW_UNIQUE_KEY_LENGTH);
148a833cb74SEtienne Carriere 		memcpy(hwkey->data, otp_key, HW_UNIQUE_KEY_LENGTH);
149a833cb74SEtienne Carriere 		ret = TEE_SUCCESS;
150a833cb74SEtienne Carriere 		goto out;
151a833cb74SEtienne Carriere 	}
1527e203c67SJorge Ramirez-Ortiz 
153a833cb74SEtienne Carriere 	if (IS_ENABLED(CFG_STM32MP15_HUK_BSEC_DERIVE_UID)) {
154a833cb74SEtienne Carriere 		ret = aes_gcm_encrypt_uid((uint8_t *)otp_key, len, hwkey->data,
155a833cb74SEtienne Carriere 					  &len);
1567e203c67SJorge Ramirez-Ortiz 		if (len != HW_UNIQUE_KEY_LENGTH)
1577e203c67SJorge Ramirez-Ortiz 			ret = TEE_ERROR_GENERIC;
158a833cb74SEtienne Carriere 		goto out;
159a833cb74SEtienne Carriere 	}
160a833cb74SEtienne Carriere 
161a833cb74SEtienne Carriere 	panic();
162a833cb74SEtienne Carriere 
1637e203c67SJorge Ramirez-Ortiz out:
1647e203c67SJorge Ramirez-Ortiz 	memzero_explicit(otp_key, HW_UNIQUE_KEY_LENGTH);
1657e203c67SJorge Ramirez-Ortiz 
1667e203c67SJorge Ramirez-Ortiz 	if (!ret && !stm32mp15_huk_init) {
1677e203c67SJorge Ramirez-Ortiz 		stm32mp15_huk_init = true;
1687e203c67SJorge Ramirez-Ortiz 		IMSG("HUK %slocked", lock ? "" : "un");
1697e203c67SJorge Ramirez-Ortiz 		DHEXDUMP(hwkey->data, HW_UNIQUE_KEY_LENGTH);
1707e203c67SJorge Ramirez-Ortiz 	}
1717e203c67SJorge Ramirez-Ortiz 
1727e203c67SJorge Ramirez-Ortiz 	return ret;
1737e203c67SJorge Ramirez-Ortiz }
1747e203c67SJorge Ramirez-Ortiz 
175