1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright 2021 Foundries.io Ltd. 4 * Jorge Ramirez-Ortiz <jorge@foundries.io> 5 */ 6 7 #include <assert.h> 8 #include <drivers/zynqmp_csu_aes.h> 9 #include <drivers/zynqmp_csu_puf.h> 10 #include <drivers/zynqmp_pm.h> 11 #include <io.h> 12 #include <kernel/tee_common_otp.h> 13 #include <mm/core_memprot.h> 14 #include <tee/tee_cryp_utl.h> 15 #include <trace.h> 16 #include <utee_defines.h> 17 18 static struct { 19 uint8_t key[HW_UNIQUE_KEY_LENGTH]; 20 bool ready; 21 } huk; 22 23 TEE_Result tee_otp_get_hw_unique_key(struct tee_hw_unique_key *hwkey) 24 { 25 vaddr_t csu = core_mmu_get_va(CSU_BASE, MEM_AREA_IO_SEC, CSU_SIZE); 26 uint8_t src[HW_UNIQUE_KEY_LENGTH] __aligned_csuaes = { 0 }; 27 uint8_t iv[ZYNQMP_EFUSE_MEM(DNA)] __aligned_efuse = { 0 }; 28 uint8_t tag[ZYNQMP_GCM_TAG_SIZE] __aligned_csuaes = { 0 }; 29 uint8_t sha[HW_UNIQUE_KEY_LENGTH] = { 0 }; 30 uint8_t dst[ZYNQMP_CSU_AES_DST_LEN(sizeof(src))] 31 __aligned_csuaes = { 0 }; 32 TEE_Result ret = TEE_ERROR_GENERIC; 33 uint32_t status = 0; 34 35 if (huk.ready) 36 goto out; 37 38 COMPILE_TIME_ASSERT(ZYNQMP_EFUSE_LEN(DNA) == ZYNQMP_GCM_IV_SIZE); 39 40 ret = zynqmp_efuse_read(iv, sizeof(iv), DNA, false); 41 if (ret) { 42 EMSG("Can't read the DNA eFuse"); 43 return ret; 44 } 45 46 if (tee_hash_createdigest(TEE_ALG_SHA256, iv, ZYNQMP_EFUSE_LEN(DNA), 47 src, sizeof(src))) { 48 EMSG("Can't generate the SHA256 for the DNA eFuse"); 49 return ret; 50 } 51 52 status = io_read32(csu + ZYNQMP_CSU_STATUS_OFFSET); 53 if (!(status & ZYNQMP_CSU_STATUS_AUTH)) { 54 /* The DNA is a unique identifier valid but not secure */ 55 IMSG("CSU authentication disabled, using development HUK"); 56 memcpy(huk.key, src, sizeof(huk.key)); 57 huk.ready = true; 58 goto out; 59 } 60 61 /* 62 * Neither the PMUFW nor the PUF hardware provide an indication of the 63 * PUF KEK registration status. The verification algorithm that follows 64 * encrypts and then decrypts the resulting string regenerating the 65 * PUF KEK in between: if the outputs match, then the PUF KEK was 66 * registered properly and we can use it to generate the HUK. 67 */ 68 zynqmp_csu_puf_reset(); 69 70 ret = zynqmp_csu_puf_regenerate(); 71 if (ret) { 72 EMSG("PUF regeneration error"); 73 return ret; 74 } 75 76 memcpy(sha, src, sizeof(sha)); 77 /* The dst buffer must be large enough to include the generated tag */ 78 ret = zynqmp_csu_aes_encrypt_data(src, sizeof(src), dst, sizeof(dst), 79 tag, sizeof(tag), iv, 80 ZYNQMP_EFUSE_LEN(DNA), 81 ZYNQMP_CSU_AES_KEY_SRC_DEV); 82 if (ret) { 83 EMSG("Can't encrypt DNA, please make sure PUF was registered"); 84 return ret; 85 } 86 87 /* regenerate the PUF KEK */ 88 ret = zynqmp_csu_puf_regenerate(); 89 if (ret) { 90 EMSG("PUF regeneration error"); 91 return ret; 92 } 93 94 memset(src, 0, sizeof(src)); 95 /* Ignore the tag data from the dst buffer - pass a smaller size */ 96 ret = zynqmp_csu_aes_decrypt_data(dst, sizeof(src), src, sizeof(src), 97 tag, sizeof(tag), iv, 98 ZYNQMP_EFUSE_LEN(DNA), 99 ZYNQMP_CSU_AES_KEY_SRC_DEV); 100 if (ret) { 101 EMSG("Can't decrypt DNA, please make sure PUF was registered"); 102 return ret; 103 } 104 105 if (memcmp(src, sha, sizeof(sha))) { 106 EMSG("PUF not ready, can't create HUK"); 107 return TEE_ERROR_GENERIC; 108 } 109 110 IMSG("HUK ready"); 111 /* 112 * The HUK is the SHA-256 DNA eFUSE string AES-GCM encrypted with the 113 * PUF KEK using the DNA eFUSE string as the IV. 114 */ 115 memcpy(huk.key, dst, sizeof(huk.key)); 116 huk.ready = true; 117 out: 118 memcpy(hwkey->data, huk.key, HW_UNIQUE_KEY_LENGTH); 119 120 return TEE_SUCCESS; 121 } 122