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
18b0946e1dSThomas BOURGOIN #define HUK_NB_OTP (HW_UNIQUE_KEY_LENGTH / sizeof(uint32_t))
19b0946e1dSThomas BOURGOIN
207e203c67SJorge Ramirez-Ortiz static bool stm32mp15_huk_init;
217e203c67SJorge Ramirez-Ortiz
stm32mp15_read_uid(uint32_t * uid)227e203c67SJorge Ramirez-Ortiz static TEE_Result stm32mp15_read_uid(uint32_t *uid)
237e203c67SJorge Ramirez-Ortiz {
2410fb0d97SGatien Chevallier TEE_Result ret = TEE_ERROR_GENERIC;
257e203c67SJorge Ramirez-Ortiz uint32_t *q = uid;
2610fb0d97SGatien Chevallier uint32_t otp_idx = 0;
2710fb0d97SGatien Chevallier size_t __maybe_unused sz = 0;
28*9f007225SPatrick Delaunay uint8_t __maybe_unused offset = 0;
2910fb0d97SGatien Chevallier
30*9f007225SPatrick Delaunay ret = stm32_bsec_find_otp_in_nvmem_layout("uid_otp", &otp_idx, &offset,
31*9f007225SPatrick Delaunay &sz);
3210fb0d97SGatien Chevallier if (ret)
3310fb0d97SGatien Chevallier return ret;
3410fb0d97SGatien Chevallier assert(sz == 3 * 32);
35*9f007225SPatrick Delaunay assert(offset == 0);
367e203c67SJorge Ramirez-Ortiz
377e203c67SJorge Ramirez-Ortiz /*
387e203c67SJorge Ramirez-Ortiz * Shadow memory for UID words might not be locked: to guarante that
397e203c67SJorge Ramirez-Ortiz * the final values are read we must lock them.
407e203c67SJorge Ramirez-Ortiz */
4110fb0d97SGatien Chevallier if (stm32_bsec_set_sw_lock(otp_idx) ||
4210fb0d97SGatien Chevallier stm32_bsec_shadow_read_otp(q++, otp_idx))
437e203c67SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC;
447e203c67SJorge Ramirez-Ortiz
4510fb0d97SGatien Chevallier if (stm32_bsec_set_sw_lock(otp_idx + 1) ||
4610fb0d97SGatien Chevallier stm32_bsec_shadow_read_otp(q++, otp_idx + 1))
477e203c67SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC;
487e203c67SJorge Ramirez-Ortiz
4910fb0d97SGatien Chevallier if (stm32_bsec_set_sw_lock(otp_idx + 2) ||
5010fb0d97SGatien Chevallier stm32_bsec_shadow_read_otp(q++, otp_idx + 2))
517e203c67SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC;
527e203c67SJorge Ramirez-Ortiz
537e203c67SJorge Ramirez-Ortiz return TEE_SUCCESS;
547e203c67SJorge Ramirez-Ortiz }
557e203c67SJorge Ramirez-Ortiz
stm32mp15_read_otp(uint32_t otp,uint32_t * key,bool * locked)567e203c67SJorge Ramirez-Ortiz static TEE_Result stm32mp15_read_otp(uint32_t otp, uint32_t *key, bool *locked)
577e203c67SJorge Ramirez-Ortiz {
587e203c67SJorge Ramirez-Ortiz bool tmp = true;
597cb0cbbaSGatien Chevallier uint32_t state = 0;
607e203c67SJorge Ramirez-Ortiz
617cb0cbbaSGatien Chevallier if (stm32_bsec_get_state(&state))
627cb0cbbaSGatien Chevallier panic();
637cb0cbbaSGatien Chevallier
647cb0cbbaSGatien Chevallier if (state != BSEC_STATE_SEC_CLOSED) {
657e203c67SJorge Ramirez-Ortiz /*
667e203c67SJorge Ramirez-Ortiz * When the device is not closed, the shadow memory for these
677e203c67SJorge Ramirez-Ortiz * words might not be locked: check and report them
687e203c67SJorge Ramirez-Ortiz */
697e203c67SJorge Ramirez-Ortiz if (stm32_bsec_read_permanent_lock(otp, &tmp))
707e203c67SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC;
717e203c67SJorge Ramirez-Ortiz
727e203c67SJorge Ramirez-Ortiz if (tmp && stm32_bsec_read_sw_lock(otp, &tmp))
737e203c67SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC;
747e203c67SJorge Ramirez-Ortiz }
757e203c67SJorge Ramirez-Ortiz
767e203c67SJorge Ramirez-Ortiz if (stm32_bsec_shadow_read_otp(key, otp))
777e203c67SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC;
787e203c67SJorge Ramirez-Ortiz
797e203c67SJorge Ramirez-Ortiz *locked = *locked && tmp;
807e203c67SJorge Ramirez-Ortiz
817e203c67SJorge Ramirez-Ortiz return TEE_SUCCESS;
827e203c67SJorge Ramirez-Ortiz }
837e203c67SJorge Ramirez-Ortiz
847e203c67SJorge Ramirez-Ortiz /*
857e203c67SJorge Ramirez-Ortiz * AES-GCM: nonce must be unique per message and key.
867e203c67SJorge Ramirez-Ortiz *
877e203c67SJorge Ramirez-Ortiz * This function always uses the same key - once its locked - with the same
887e203c67SJorge Ramirez-Ortiz * unique message hence the nonce can be any constant.
897e203c67SJorge Ramirez-Ortiz */
aes_gcm_encrypt_uid(uint8_t * key,size_t key_len,uint8_t * out,size_t * out_len)907e203c67SJorge Ramirez-Ortiz static TEE_Result aes_gcm_encrypt_uid(uint8_t *key, size_t key_len,
917e203c67SJorge Ramirez-Ortiz uint8_t *out, size_t *out_len)
927e203c67SJorge Ramirez-Ortiz {
937e203c67SJorge Ramirez-Ortiz TEE_Result ret = TEE_ERROR_GENERIC;
947e203c67SJorge Ramirez-Ortiz const uint8_t nonce[12] = { 0x55 };
957e203c67SJorge Ramirez-Ortiz uint32_t uid[4] = { 0 };
967e203c67SJorge Ramirez-Ortiz uint8_t tag[16] = { 0 };
977e203c67SJorge Ramirez-Ortiz size_t nonce_len = sizeof(nonce);
987e203c67SJorge Ramirez-Ortiz size_t tag_len = sizeof(tag);
997e203c67SJorge Ramirez-Ortiz size_t uid_len = sizeof(uid);
1007e203c67SJorge Ramirez-Ortiz void *ctx = NULL;
1017e203c67SJorge Ramirez-Ortiz
1027e203c67SJorge Ramirez-Ortiz ret = stm32mp15_read_uid(uid);
1037e203c67SJorge Ramirez-Ortiz if (ret)
1047e203c67SJorge Ramirez-Ortiz goto out;
1057e203c67SJorge Ramirez-Ortiz
1067e203c67SJorge Ramirez-Ortiz ret = crypto_authenc_alloc_ctx(&ctx, TEE_ALG_AES_GCM);
1077e203c67SJorge Ramirez-Ortiz if (ret)
1087e203c67SJorge Ramirez-Ortiz goto out;
1097e203c67SJorge Ramirez-Ortiz
1107e203c67SJorge Ramirez-Ortiz ret = crypto_authenc_init(ctx, TEE_MODE_ENCRYPT, key, key_len, nonce,
1117e203c67SJorge Ramirez-Ortiz nonce_len, TEE_AES_BLOCK_SIZE, 0, uid_len);
1127e203c67SJorge Ramirez-Ortiz if (ret)
1137e203c67SJorge Ramirez-Ortiz goto out_free_ctx;
1147e203c67SJorge Ramirez-Ortiz
1157e203c67SJorge Ramirez-Ortiz ret = crypto_authenc_enc_final(ctx, (uint8_t *)uid, sizeof(uid),
1167e203c67SJorge Ramirez-Ortiz out, out_len, tag, &tag_len);
1177e203c67SJorge Ramirez-Ortiz if (ret)
1187e203c67SJorge Ramirez-Ortiz goto out_free_ctx;
1197e203c67SJorge Ramirez-Ortiz
1207e203c67SJorge Ramirez-Ortiz crypto_authenc_final(ctx);
1217e203c67SJorge Ramirez-Ortiz out_free_ctx:
1227e203c67SJorge Ramirez-Ortiz crypto_authenc_free_ctx(ctx);
1237e203c67SJorge Ramirez-Ortiz out:
1247e203c67SJorge Ramirez-Ortiz if (ret)
1257e203c67SJorge Ramirez-Ortiz memzero_explicit(out, *out_len);
1267e203c67SJorge Ramirez-Ortiz
1277e203c67SJorge Ramirez-Ortiz return ret;
1287e203c67SJorge Ramirez-Ortiz }
1297e203c67SJorge Ramirez-Ortiz
pos_from_dt(uint32_t otp_id[HUK_NB_OTP])130b0946e1dSThomas BOURGOIN static __maybe_unused TEE_Result pos_from_dt(uint32_t otp_id[HUK_NB_OTP])
1317e203c67SJorge Ramirez-Ortiz {
1327e203c67SJorge Ramirez-Ortiz TEE_Result ret = TEE_SUCCESS;
133b0946e1dSThomas BOURGOIN uint32_t otp_start = 0;
134*9f007225SPatrick Delaunay size_t sz = 0;
135*9f007225SPatrick Delaunay uint8_t offset = 0;
136b0946e1dSThomas BOURGOIN size_t i = 0;
137b0946e1dSThomas BOURGOIN
138*9f007225SPatrick Delaunay ret = stm32_bsec_find_otp_in_nvmem_layout("huk-otp", &otp_start,
139*9f007225SPatrick Delaunay &offset, &sz);
140b0946e1dSThomas BOURGOIN if (ret)
141b0946e1dSThomas BOURGOIN return ret;
142b0946e1dSThomas BOURGOIN
143*9f007225SPatrick Delaunay if (sz != (HW_UNIQUE_KEY_LENGTH * CHAR_BIT) || offset != 0)
144b0946e1dSThomas BOURGOIN return TEE_ERROR_SECURITY;
145b0946e1dSThomas BOURGOIN
146b0946e1dSThomas BOURGOIN for (i = 0; i < HUK_NB_OTP; i++)
147b0946e1dSThomas BOURGOIN otp_id[i] = otp_start + i;
148b0946e1dSThomas BOURGOIN
149b0946e1dSThomas BOURGOIN return TEE_SUCCESS;
150b0946e1dSThomas BOURGOIN }
151b0946e1dSThomas BOURGOIN
get_otp_pos(uint32_t otp_id[HUK_NB_OTP])152b0946e1dSThomas BOURGOIN static TEE_Result get_otp_pos(uint32_t otp_id[HUK_NB_OTP])
153b0946e1dSThomas BOURGOIN {
154b0946e1dSThomas BOURGOIN #ifdef CFG_STM32_HUK_FROM_DT
155b0946e1dSThomas BOURGOIN return pos_from_dt(otp_id);
156b0946e1dSThomas BOURGOIN #else /* CFG_STM32_HUK_FROM_DT */
1577e203c67SJorge Ramirez-Ortiz
1587e203c67SJorge Ramirez-Ortiz static_assert(CFG_STM32MP15_HUK_BSEC_KEY_0 < STM32MP1_OTP_MAX_ID);
1597e203c67SJorge Ramirez-Ortiz static_assert(CFG_STM32MP15_HUK_BSEC_KEY_1 < STM32MP1_OTP_MAX_ID);
1607e203c67SJorge Ramirez-Ortiz static_assert(CFG_STM32MP15_HUK_BSEC_KEY_2 < STM32MP1_OTP_MAX_ID);
1617e203c67SJorge Ramirez-Ortiz static_assert(CFG_STM32MP15_HUK_BSEC_KEY_3 < STM32MP1_OTP_MAX_ID);
1627e203c67SJorge Ramirez-Ortiz
163b0946e1dSThomas BOURGOIN otp_id[0] = CFG_STM32MP15_HUK_BSEC_KEY_0;
164b0946e1dSThomas BOURGOIN otp_id[1] = CFG_STM32MP15_HUK_BSEC_KEY_1;
165b0946e1dSThomas BOURGOIN otp_id[2] = CFG_STM32MP15_HUK_BSEC_KEY_2;
166b0946e1dSThomas BOURGOIN otp_id[3] = CFG_STM32MP15_HUK_BSEC_KEY_3;
1677e203c67SJorge Ramirez-Ortiz
168b0946e1dSThomas BOURGOIN return TEE_SUCCESS;
169b0946e1dSThomas BOURGOIN #endif /* CFG_STM32_HUK_FROM_DT */
170b0946e1dSThomas BOURGOIN }
1717e203c67SJorge Ramirez-Ortiz
tee_otp_get_hw_unique_key(struct tee_hw_unique_key * hwkey)172b0946e1dSThomas BOURGOIN TEE_Result tee_otp_get_hw_unique_key(struct tee_hw_unique_key *hwkey)
173b0946e1dSThomas BOURGOIN {
174b0946e1dSThomas BOURGOIN uint32_t otp_key[HUK_NB_OTP] = { };
175b0946e1dSThomas BOURGOIN uint32_t otp_id[HUK_NB_OTP] = { };
176b0946e1dSThomas BOURGOIN size_t len = HW_UNIQUE_KEY_LENGTH;
177b0946e1dSThomas BOURGOIN TEE_Result ret = TEE_SUCCESS;
178b0946e1dSThomas BOURGOIN uint32_t *key = otp_key;
179b0946e1dSThomas BOURGOIN bool lock = true;
180b0946e1dSThomas BOURGOIN size_t i = 0;
1817e203c67SJorge Ramirez-Ortiz
182b0946e1dSThomas BOURGOIN ret = get_otp_pos(otp_id);
183b0946e1dSThomas BOURGOIN if (ret)
184b0946e1dSThomas BOURGOIN return ret;
185b0946e1dSThomas BOURGOIN
186b0946e1dSThomas BOURGOIN for (i = 0; i < HUK_NB_OTP; i++) {
187b0946e1dSThomas BOURGOIN ret = stm32mp15_read_otp(otp_id[i], key++, &lock);
1887e203c67SJorge Ramirez-Ortiz if (ret)
1897e203c67SJorge Ramirez-Ortiz goto out;
190b0946e1dSThomas BOURGOIN }
1917e203c67SJorge Ramirez-Ortiz
192a833cb74SEtienne Carriere if (IS_ENABLED(CFG_STM32MP15_HUK_BSEC_KEY)) {
193a833cb74SEtienne Carriere static_assert(sizeof(otp_key) == HW_UNIQUE_KEY_LENGTH);
194a833cb74SEtienne Carriere memcpy(hwkey->data, otp_key, HW_UNIQUE_KEY_LENGTH);
195a833cb74SEtienne Carriere ret = TEE_SUCCESS;
196a833cb74SEtienne Carriere goto out;
197a833cb74SEtienne Carriere }
1987e203c67SJorge Ramirez-Ortiz
199a833cb74SEtienne Carriere if (IS_ENABLED(CFG_STM32MP15_HUK_BSEC_DERIVE_UID)) {
200a833cb74SEtienne Carriere ret = aes_gcm_encrypt_uid((uint8_t *)otp_key, len, hwkey->data,
201a833cb74SEtienne Carriere &len);
2027e203c67SJorge Ramirez-Ortiz if (len != HW_UNIQUE_KEY_LENGTH)
2037e203c67SJorge Ramirez-Ortiz ret = TEE_ERROR_GENERIC;
204a833cb74SEtienne Carriere goto out;
205a833cb74SEtienne Carriere }
206a833cb74SEtienne Carriere
207a833cb74SEtienne Carriere panic();
208a833cb74SEtienne Carriere
2097e203c67SJorge Ramirez-Ortiz out:
2107e203c67SJorge Ramirez-Ortiz memzero_explicit(otp_key, HW_UNIQUE_KEY_LENGTH);
2117e203c67SJorge Ramirez-Ortiz
2127e203c67SJorge Ramirez-Ortiz if (!ret && !stm32mp15_huk_init) {
2137e203c67SJorge Ramirez-Ortiz stm32mp15_huk_init = true;
2147e203c67SJorge Ramirez-Ortiz IMSG("HUK %slocked", lock ? "" : "un");
2157e203c67SJorge Ramirez-Ortiz DHEXDUMP(hwkey->data, HW_UNIQUE_KEY_LENGTH);
2167e203c67SJorge Ramirez-Ortiz }
2177e203c67SJorge Ramirez-Ortiz
2187e203c67SJorge Ramirez-Ortiz return ret;
2197e203c67SJorge Ramirez-Ortiz }
2207e203c67SJorge Ramirez-Ortiz
221