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; 467e203c67SJorge Ramirez-Ortiz 477e203c67SJorge Ramirez-Ortiz if (!stm32mp_is_closed_device()) { 487e203c67SJorge Ramirez-Ortiz /* 497e203c67SJorge Ramirez-Ortiz * When the device is not closed, the shadow memory for these 507e203c67SJorge Ramirez-Ortiz * words might not be locked: check and report them 517e203c67SJorge Ramirez-Ortiz */ 527e203c67SJorge Ramirez-Ortiz if (stm32_bsec_read_permanent_lock(otp, &tmp)) 537e203c67SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 547e203c67SJorge Ramirez-Ortiz 557e203c67SJorge Ramirez-Ortiz if (tmp && stm32_bsec_read_sw_lock(otp, &tmp)) 567e203c67SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 577e203c67SJorge Ramirez-Ortiz } 587e203c67SJorge Ramirez-Ortiz 597e203c67SJorge Ramirez-Ortiz if (stm32_bsec_shadow_read_otp(key, otp)) 607e203c67SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 617e203c67SJorge Ramirez-Ortiz 627e203c67SJorge Ramirez-Ortiz *locked = *locked && tmp; 637e203c67SJorge Ramirez-Ortiz 647e203c67SJorge Ramirez-Ortiz return TEE_SUCCESS; 657e203c67SJorge Ramirez-Ortiz } 667e203c67SJorge Ramirez-Ortiz 677e203c67SJorge Ramirez-Ortiz /* 687e203c67SJorge Ramirez-Ortiz * AES-GCM: nonce must be unique per message and key. 697e203c67SJorge Ramirez-Ortiz * 707e203c67SJorge Ramirez-Ortiz * This function always uses the same key - once its locked - with the same 717e203c67SJorge Ramirez-Ortiz * unique message hence the nonce can be any constant. 727e203c67SJorge Ramirez-Ortiz */ 737e203c67SJorge Ramirez-Ortiz static TEE_Result aes_gcm_encrypt_uid(uint8_t *key, size_t key_len, 747e203c67SJorge Ramirez-Ortiz uint8_t *out, size_t *out_len) 757e203c67SJorge Ramirez-Ortiz { 767e203c67SJorge Ramirez-Ortiz TEE_Result ret = TEE_ERROR_GENERIC; 777e203c67SJorge Ramirez-Ortiz const uint8_t nonce[12] = { 0x55 }; 787e203c67SJorge Ramirez-Ortiz uint32_t uid[4] = { 0 }; 797e203c67SJorge Ramirez-Ortiz uint8_t tag[16] = { 0 }; 807e203c67SJorge Ramirez-Ortiz size_t nonce_len = sizeof(nonce); 817e203c67SJorge Ramirez-Ortiz size_t tag_len = sizeof(tag); 827e203c67SJorge Ramirez-Ortiz size_t uid_len = sizeof(uid); 837e203c67SJorge Ramirez-Ortiz void *ctx = NULL; 847e203c67SJorge Ramirez-Ortiz 857e203c67SJorge Ramirez-Ortiz ret = stm32mp15_read_uid(uid); 867e203c67SJorge Ramirez-Ortiz if (ret) 877e203c67SJorge Ramirez-Ortiz goto out; 887e203c67SJorge Ramirez-Ortiz 897e203c67SJorge Ramirez-Ortiz ret = crypto_authenc_alloc_ctx(&ctx, TEE_ALG_AES_GCM); 907e203c67SJorge Ramirez-Ortiz if (ret) 917e203c67SJorge Ramirez-Ortiz goto out; 927e203c67SJorge Ramirez-Ortiz 937e203c67SJorge Ramirez-Ortiz ret = crypto_authenc_init(ctx, TEE_MODE_ENCRYPT, key, key_len, nonce, 947e203c67SJorge Ramirez-Ortiz nonce_len, TEE_AES_BLOCK_SIZE, 0, uid_len); 957e203c67SJorge Ramirez-Ortiz if (ret) 967e203c67SJorge Ramirez-Ortiz goto out_free_ctx; 977e203c67SJorge Ramirez-Ortiz 987e203c67SJorge Ramirez-Ortiz ret = crypto_authenc_enc_final(ctx, (uint8_t *)uid, sizeof(uid), 997e203c67SJorge Ramirez-Ortiz out, out_len, tag, &tag_len); 1007e203c67SJorge Ramirez-Ortiz if (ret) 1017e203c67SJorge Ramirez-Ortiz goto out_free_ctx; 1027e203c67SJorge Ramirez-Ortiz 1037e203c67SJorge Ramirez-Ortiz crypto_authenc_final(ctx); 1047e203c67SJorge Ramirez-Ortiz out_free_ctx: 1057e203c67SJorge Ramirez-Ortiz crypto_authenc_free_ctx(ctx); 1067e203c67SJorge Ramirez-Ortiz out: 1077e203c67SJorge Ramirez-Ortiz if (ret) 1087e203c67SJorge Ramirez-Ortiz memzero_explicit(out, *out_len); 1097e203c67SJorge Ramirez-Ortiz 1107e203c67SJorge Ramirez-Ortiz return ret; 1117e203c67SJorge Ramirez-Ortiz } 1127e203c67SJorge Ramirez-Ortiz 1137e203c67SJorge Ramirez-Ortiz TEE_Result tee_otp_get_hw_unique_key(struct tee_hw_unique_key *hwkey) 1147e203c67SJorge Ramirez-Ortiz { 1157e203c67SJorge Ramirez-Ortiz uint32_t otp_key[4] = { 0 }; 1167e203c67SJorge Ramirez-Ortiz size_t len = sizeof(otp_key); 1177e203c67SJorge Ramirez-Ortiz TEE_Result ret = TEE_SUCCESS; 1187e203c67SJorge Ramirez-Ortiz uint32_t *key = otp_key; 1197e203c67SJorge Ramirez-Ortiz bool lock = true; 1207e203c67SJorge Ramirez-Ortiz 1217e203c67SJorge Ramirez-Ortiz static_assert(CFG_STM32MP15_HUK_BSEC_KEY_0 < STM32MP1_OTP_MAX_ID); 1227e203c67SJorge Ramirez-Ortiz static_assert(CFG_STM32MP15_HUK_BSEC_KEY_1 < STM32MP1_OTP_MAX_ID); 1237e203c67SJorge Ramirez-Ortiz static_assert(CFG_STM32MP15_HUK_BSEC_KEY_2 < STM32MP1_OTP_MAX_ID); 1247e203c67SJorge Ramirez-Ortiz static_assert(CFG_STM32MP15_HUK_BSEC_KEY_3 < STM32MP1_OTP_MAX_ID); 1257e203c67SJorge Ramirez-Ortiz 1267e203c67SJorge Ramirez-Ortiz ret = stm32mp15_read_otp(CFG_STM32MP15_HUK_BSEC_KEY_0, key++, &lock); 1277e203c67SJorge Ramirez-Ortiz if (ret) 1287e203c67SJorge Ramirez-Ortiz goto out; 1297e203c67SJorge Ramirez-Ortiz 1307e203c67SJorge Ramirez-Ortiz ret = stm32mp15_read_otp(CFG_STM32MP15_HUK_BSEC_KEY_1, 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_2, 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_3, key++, &lock); 1397e203c67SJorge Ramirez-Ortiz if (ret) 1407e203c67SJorge Ramirez-Ortiz goto out; 1417e203c67SJorge Ramirez-Ortiz 142*a833cb74SEtienne Carriere if (IS_ENABLED(CFG_STM32MP15_HUK_BSEC_KEY)) { 143*a833cb74SEtienne Carriere static_assert(sizeof(otp_key) == HW_UNIQUE_KEY_LENGTH); 144*a833cb74SEtienne Carriere memcpy(hwkey->data, otp_key, HW_UNIQUE_KEY_LENGTH); 145*a833cb74SEtienne Carriere ret = TEE_SUCCESS; 146*a833cb74SEtienne Carriere goto out; 147*a833cb74SEtienne Carriere } 1487e203c67SJorge Ramirez-Ortiz 149*a833cb74SEtienne Carriere if (IS_ENABLED(CFG_STM32MP15_HUK_BSEC_DERIVE_UID)) { 150*a833cb74SEtienne Carriere ret = aes_gcm_encrypt_uid((uint8_t *)otp_key, len, hwkey->data, 151*a833cb74SEtienne Carriere &len); 1527e203c67SJorge Ramirez-Ortiz if (len != HW_UNIQUE_KEY_LENGTH) 1537e203c67SJorge Ramirez-Ortiz ret = TEE_ERROR_GENERIC; 154*a833cb74SEtienne Carriere goto out; 155*a833cb74SEtienne Carriere } 156*a833cb74SEtienne Carriere 157*a833cb74SEtienne Carriere panic(); 158*a833cb74SEtienne Carriere 1597e203c67SJorge Ramirez-Ortiz out: 1607e203c67SJorge Ramirez-Ortiz memzero_explicit(otp_key, HW_UNIQUE_KEY_LENGTH); 1617e203c67SJorge Ramirez-Ortiz 1627e203c67SJorge Ramirez-Ortiz if (!ret && !stm32mp15_huk_init) { 1637e203c67SJorge Ramirez-Ortiz stm32mp15_huk_init = true; 1647e203c67SJorge Ramirez-Ortiz IMSG("HUK %slocked", lock ? "" : "un"); 1657e203c67SJorge Ramirez-Ortiz DHEXDUMP(hwkey->data, HW_UNIQUE_KEY_LENGTH); 1667e203c67SJorge Ramirez-Ortiz } 1677e203c67SJorge Ramirez-Ortiz 1687e203c67SJorge Ramirez-Ortiz return ret; 1697e203c67SJorge Ramirez-Ortiz } 1707e203c67SJorge Ramirez-Ortiz 171