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
tee_otp_get_hw_unique_key(struct tee_hw_unique_key * hwkey)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