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 18*b0946e1dSThomas BOURGOIN #define HUK_NB_OTP (HW_UNIQUE_KEY_LENGTH / sizeof(uint32_t)) 19*b0946e1dSThomas BOURGOIN 207e203c67SJorge Ramirez-Ortiz static bool stm32mp15_huk_init; 217e203c67SJorge Ramirez-Ortiz 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; 2810fb0d97SGatien Chevallier 2910fb0d97SGatien Chevallier ret = stm32_bsec_find_otp_in_nvmem_layout("uid_otp", &otp_idx, &sz); 3010fb0d97SGatien Chevallier if (ret) 3110fb0d97SGatien Chevallier return ret; 3210fb0d97SGatien Chevallier assert(sz == 3 * 32); 337e203c67SJorge Ramirez-Ortiz 347e203c67SJorge Ramirez-Ortiz /* 357e203c67SJorge Ramirez-Ortiz * Shadow memory for UID words might not be locked: to guarante that 367e203c67SJorge Ramirez-Ortiz * the final values are read we must lock them. 377e203c67SJorge Ramirez-Ortiz */ 3810fb0d97SGatien Chevallier if (stm32_bsec_set_sw_lock(otp_idx) || 3910fb0d97SGatien Chevallier stm32_bsec_shadow_read_otp(q++, otp_idx)) 407e203c67SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 417e203c67SJorge Ramirez-Ortiz 4210fb0d97SGatien Chevallier if (stm32_bsec_set_sw_lock(otp_idx + 1) || 4310fb0d97SGatien Chevallier stm32_bsec_shadow_read_otp(q++, otp_idx + 1)) 447e203c67SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 457e203c67SJorge Ramirez-Ortiz 4610fb0d97SGatien Chevallier if (stm32_bsec_set_sw_lock(otp_idx + 2) || 4710fb0d97SGatien Chevallier stm32_bsec_shadow_read_otp(q++, otp_idx + 2)) 487e203c67SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 497e203c67SJorge Ramirez-Ortiz 507e203c67SJorge Ramirez-Ortiz return TEE_SUCCESS; 517e203c67SJorge Ramirez-Ortiz } 527e203c67SJorge Ramirez-Ortiz 537e203c67SJorge Ramirez-Ortiz static TEE_Result stm32mp15_read_otp(uint32_t otp, uint32_t *key, bool *locked) 547e203c67SJorge Ramirez-Ortiz { 557e203c67SJorge Ramirez-Ortiz bool tmp = true; 567cb0cbbaSGatien Chevallier uint32_t state = 0; 577e203c67SJorge Ramirez-Ortiz 587cb0cbbaSGatien Chevallier if (stm32_bsec_get_state(&state)) 597cb0cbbaSGatien Chevallier panic(); 607cb0cbbaSGatien Chevallier 617cb0cbbaSGatien Chevallier if (state != BSEC_STATE_SEC_CLOSED) { 627e203c67SJorge Ramirez-Ortiz /* 637e203c67SJorge Ramirez-Ortiz * When the device is not closed, the shadow memory for these 647e203c67SJorge Ramirez-Ortiz * words might not be locked: check and report them 657e203c67SJorge Ramirez-Ortiz */ 667e203c67SJorge Ramirez-Ortiz if (stm32_bsec_read_permanent_lock(otp, &tmp)) 677e203c67SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 687e203c67SJorge Ramirez-Ortiz 697e203c67SJorge Ramirez-Ortiz if (tmp && stm32_bsec_read_sw_lock(otp, &tmp)) 707e203c67SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 717e203c67SJorge Ramirez-Ortiz } 727e203c67SJorge Ramirez-Ortiz 737e203c67SJorge Ramirez-Ortiz if (stm32_bsec_shadow_read_otp(key, otp)) 747e203c67SJorge Ramirez-Ortiz return TEE_ERROR_GENERIC; 757e203c67SJorge Ramirez-Ortiz 767e203c67SJorge Ramirez-Ortiz *locked = *locked && tmp; 777e203c67SJorge Ramirez-Ortiz 787e203c67SJorge Ramirez-Ortiz return TEE_SUCCESS; 797e203c67SJorge Ramirez-Ortiz } 807e203c67SJorge Ramirez-Ortiz 817e203c67SJorge Ramirez-Ortiz /* 827e203c67SJorge Ramirez-Ortiz * AES-GCM: nonce must be unique per message and key. 837e203c67SJorge Ramirez-Ortiz * 847e203c67SJorge Ramirez-Ortiz * This function always uses the same key - once its locked - with the same 857e203c67SJorge Ramirez-Ortiz * unique message hence the nonce can be any constant. 867e203c67SJorge Ramirez-Ortiz */ 877e203c67SJorge Ramirez-Ortiz static TEE_Result aes_gcm_encrypt_uid(uint8_t *key, size_t key_len, 887e203c67SJorge Ramirez-Ortiz uint8_t *out, size_t *out_len) 897e203c67SJorge Ramirez-Ortiz { 907e203c67SJorge Ramirez-Ortiz TEE_Result ret = TEE_ERROR_GENERIC; 917e203c67SJorge Ramirez-Ortiz const uint8_t nonce[12] = { 0x55 }; 927e203c67SJorge Ramirez-Ortiz uint32_t uid[4] = { 0 }; 937e203c67SJorge Ramirez-Ortiz uint8_t tag[16] = { 0 }; 947e203c67SJorge Ramirez-Ortiz size_t nonce_len = sizeof(nonce); 957e203c67SJorge Ramirez-Ortiz size_t tag_len = sizeof(tag); 967e203c67SJorge Ramirez-Ortiz size_t uid_len = sizeof(uid); 977e203c67SJorge Ramirez-Ortiz void *ctx = NULL; 987e203c67SJorge Ramirez-Ortiz 997e203c67SJorge Ramirez-Ortiz ret = stm32mp15_read_uid(uid); 1007e203c67SJorge Ramirez-Ortiz if (ret) 1017e203c67SJorge Ramirez-Ortiz goto out; 1027e203c67SJorge Ramirez-Ortiz 1037e203c67SJorge Ramirez-Ortiz ret = crypto_authenc_alloc_ctx(&ctx, TEE_ALG_AES_GCM); 1047e203c67SJorge Ramirez-Ortiz if (ret) 1057e203c67SJorge Ramirez-Ortiz goto out; 1067e203c67SJorge Ramirez-Ortiz 1077e203c67SJorge Ramirez-Ortiz ret = crypto_authenc_init(ctx, TEE_MODE_ENCRYPT, key, key_len, nonce, 1087e203c67SJorge Ramirez-Ortiz nonce_len, TEE_AES_BLOCK_SIZE, 0, uid_len); 1097e203c67SJorge Ramirez-Ortiz if (ret) 1107e203c67SJorge Ramirez-Ortiz goto out_free_ctx; 1117e203c67SJorge Ramirez-Ortiz 1127e203c67SJorge Ramirez-Ortiz ret = crypto_authenc_enc_final(ctx, (uint8_t *)uid, sizeof(uid), 1137e203c67SJorge Ramirez-Ortiz out, out_len, tag, &tag_len); 1147e203c67SJorge Ramirez-Ortiz if (ret) 1157e203c67SJorge Ramirez-Ortiz goto out_free_ctx; 1167e203c67SJorge Ramirez-Ortiz 1177e203c67SJorge Ramirez-Ortiz crypto_authenc_final(ctx); 1187e203c67SJorge Ramirez-Ortiz out_free_ctx: 1197e203c67SJorge Ramirez-Ortiz crypto_authenc_free_ctx(ctx); 1207e203c67SJorge Ramirez-Ortiz out: 1217e203c67SJorge Ramirez-Ortiz if (ret) 1227e203c67SJorge Ramirez-Ortiz memzero_explicit(out, *out_len); 1237e203c67SJorge Ramirez-Ortiz 1247e203c67SJorge Ramirez-Ortiz return ret; 1257e203c67SJorge Ramirez-Ortiz } 1267e203c67SJorge Ramirez-Ortiz 127*b0946e1dSThomas BOURGOIN static __maybe_unused TEE_Result pos_from_dt(uint32_t otp_id[HUK_NB_OTP]) 1287e203c67SJorge Ramirez-Ortiz { 1297e203c67SJorge Ramirez-Ortiz TEE_Result ret = TEE_SUCCESS; 130*b0946e1dSThomas BOURGOIN uint32_t otp_start = 0; 131*b0946e1dSThomas BOURGOIN size_t tmp = 0; 132*b0946e1dSThomas BOURGOIN size_t i = 0; 133*b0946e1dSThomas BOURGOIN 134*b0946e1dSThomas BOURGOIN ret = stm32_bsec_find_otp_in_nvmem_layout("huk-otp", &otp_start, &tmp); 135*b0946e1dSThomas BOURGOIN if (ret) 136*b0946e1dSThomas BOURGOIN return ret; 137*b0946e1dSThomas BOURGOIN 138*b0946e1dSThomas BOURGOIN if (tmp != (HW_UNIQUE_KEY_LENGTH * CHAR_BIT)) 139*b0946e1dSThomas BOURGOIN return TEE_ERROR_SECURITY; 140*b0946e1dSThomas BOURGOIN 141*b0946e1dSThomas BOURGOIN for (i = 0; i < HUK_NB_OTP; i++) 142*b0946e1dSThomas BOURGOIN otp_id[i] = otp_start + i; 143*b0946e1dSThomas BOURGOIN 144*b0946e1dSThomas BOURGOIN return TEE_SUCCESS; 145*b0946e1dSThomas BOURGOIN } 146*b0946e1dSThomas BOURGOIN 147*b0946e1dSThomas BOURGOIN static TEE_Result get_otp_pos(uint32_t otp_id[HUK_NB_OTP]) 148*b0946e1dSThomas BOURGOIN { 149*b0946e1dSThomas BOURGOIN #ifdef CFG_STM32_HUK_FROM_DT 150*b0946e1dSThomas BOURGOIN return pos_from_dt(otp_id); 151*b0946e1dSThomas BOURGOIN #else /* CFG_STM32_HUK_FROM_DT */ 1527e203c67SJorge Ramirez-Ortiz 1537e203c67SJorge Ramirez-Ortiz static_assert(CFG_STM32MP15_HUK_BSEC_KEY_0 < STM32MP1_OTP_MAX_ID); 1547e203c67SJorge Ramirez-Ortiz static_assert(CFG_STM32MP15_HUK_BSEC_KEY_1 < STM32MP1_OTP_MAX_ID); 1557e203c67SJorge Ramirez-Ortiz static_assert(CFG_STM32MP15_HUK_BSEC_KEY_2 < STM32MP1_OTP_MAX_ID); 1567e203c67SJorge Ramirez-Ortiz static_assert(CFG_STM32MP15_HUK_BSEC_KEY_3 < STM32MP1_OTP_MAX_ID); 1577e203c67SJorge Ramirez-Ortiz 158*b0946e1dSThomas BOURGOIN otp_id[0] = CFG_STM32MP15_HUK_BSEC_KEY_0; 159*b0946e1dSThomas BOURGOIN otp_id[1] = CFG_STM32MP15_HUK_BSEC_KEY_1; 160*b0946e1dSThomas BOURGOIN otp_id[2] = CFG_STM32MP15_HUK_BSEC_KEY_2; 161*b0946e1dSThomas BOURGOIN otp_id[3] = CFG_STM32MP15_HUK_BSEC_KEY_3; 1627e203c67SJorge Ramirez-Ortiz 163*b0946e1dSThomas BOURGOIN return TEE_SUCCESS; 164*b0946e1dSThomas BOURGOIN #endif /* CFG_STM32_HUK_FROM_DT */ 165*b0946e1dSThomas BOURGOIN } 1667e203c67SJorge Ramirez-Ortiz 167*b0946e1dSThomas BOURGOIN TEE_Result tee_otp_get_hw_unique_key(struct tee_hw_unique_key *hwkey) 168*b0946e1dSThomas BOURGOIN { 169*b0946e1dSThomas BOURGOIN uint32_t otp_key[HUK_NB_OTP] = { }; 170*b0946e1dSThomas BOURGOIN uint32_t otp_id[HUK_NB_OTP] = { }; 171*b0946e1dSThomas BOURGOIN size_t len = HW_UNIQUE_KEY_LENGTH; 172*b0946e1dSThomas BOURGOIN TEE_Result ret = TEE_SUCCESS; 173*b0946e1dSThomas BOURGOIN uint32_t *key = otp_key; 174*b0946e1dSThomas BOURGOIN bool lock = true; 175*b0946e1dSThomas BOURGOIN size_t i = 0; 1767e203c67SJorge Ramirez-Ortiz 177*b0946e1dSThomas BOURGOIN ret = get_otp_pos(otp_id); 178*b0946e1dSThomas BOURGOIN if (ret) 179*b0946e1dSThomas BOURGOIN return ret; 180*b0946e1dSThomas BOURGOIN 181*b0946e1dSThomas BOURGOIN for (i = 0; i < HUK_NB_OTP; i++) { 182*b0946e1dSThomas BOURGOIN ret = stm32mp15_read_otp(otp_id[i], key++, &lock); 1837e203c67SJorge Ramirez-Ortiz if (ret) 1847e203c67SJorge Ramirez-Ortiz goto out; 185*b0946e1dSThomas BOURGOIN } 1867e203c67SJorge Ramirez-Ortiz 187a833cb74SEtienne Carriere if (IS_ENABLED(CFG_STM32MP15_HUK_BSEC_KEY)) { 188a833cb74SEtienne Carriere static_assert(sizeof(otp_key) == HW_UNIQUE_KEY_LENGTH); 189a833cb74SEtienne Carriere memcpy(hwkey->data, otp_key, HW_UNIQUE_KEY_LENGTH); 190a833cb74SEtienne Carriere ret = TEE_SUCCESS; 191a833cb74SEtienne Carriere goto out; 192a833cb74SEtienne Carriere } 1937e203c67SJorge Ramirez-Ortiz 194a833cb74SEtienne Carriere if (IS_ENABLED(CFG_STM32MP15_HUK_BSEC_DERIVE_UID)) { 195a833cb74SEtienne Carriere ret = aes_gcm_encrypt_uid((uint8_t *)otp_key, len, hwkey->data, 196a833cb74SEtienne Carriere &len); 1977e203c67SJorge Ramirez-Ortiz if (len != HW_UNIQUE_KEY_LENGTH) 1987e203c67SJorge Ramirez-Ortiz ret = TEE_ERROR_GENERIC; 199a833cb74SEtienne Carriere goto out; 200a833cb74SEtienne Carriere } 201a833cb74SEtienne Carriere 202a833cb74SEtienne Carriere panic(); 203a833cb74SEtienne Carriere 2047e203c67SJorge Ramirez-Ortiz out: 2057e203c67SJorge Ramirez-Ortiz memzero_explicit(otp_key, HW_UNIQUE_KEY_LENGTH); 2067e203c67SJorge Ramirez-Ortiz 2077e203c67SJorge Ramirez-Ortiz if (!ret && !stm32mp15_huk_init) { 2087e203c67SJorge Ramirez-Ortiz stm32mp15_huk_init = true; 2097e203c67SJorge Ramirez-Ortiz IMSG("HUK %slocked", lock ? "" : "un"); 2107e203c67SJorge Ramirez-Ortiz DHEXDUMP(hwkey->data, HW_UNIQUE_KEY_LENGTH); 2117e203c67SJorge Ramirez-Ortiz } 2127e203c67SJorge Ramirez-Ortiz 2137e203c67SJorge Ramirez-Ortiz return ret; 2147e203c67SJorge Ramirez-Ortiz } 2157e203c67SJorge Ramirez-Ortiz 216