11d23b02eSJorge Ramirez-Ortiz // SPDX-License-Identifier: BSD-2-Clause
21d23b02eSJorge Ramirez-Ortiz /*
31d23b02eSJorge Ramirez-Ortiz * Copyright 2021 Foundries.io Ltd.
41d23b02eSJorge Ramirez-Ortiz * Jorge Ramirez-Ortiz <jorge@foundries.io>
51d23b02eSJorge Ramirez-Ortiz */
61d23b02eSJorge Ramirez-Ortiz
71d23b02eSJorge Ramirez-Ortiz #include <assert.h>
81d23b02eSJorge Ramirez-Ortiz #include <drivers/zynqmp_csu_aes.h>
91d23b02eSJorge Ramirez-Ortiz #include <drivers/zynqmp_csu_puf.h>
10*dfeed924SVesa Jääskeläinen #include <drivers/zynqmp_huk.h>
111d23b02eSJorge Ramirez-Ortiz #include <drivers/zynqmp_pm.h>
121d23b02eSJorge Ramirez-Ortiz #include <io.h>
131d23b02eSJorge Ramirez-Ortiz #include <kernel/tee_common_otp.h>
141d23b02eSJorge Ramirez-Ortiz #include <mm/core_memprot.h>
15*dfeed924SVesa Jääskeläinen #include <string_ext.h>
161d23b02eSJorge Ramirez-Ortiz #include <tee/tee_cryp_utl.h>
171d23b02eSJorge Ramirez-Ortiz #include <trace.h>
181d23b02eSJorge Ramirez-Ortiz #include <utee_defines.h>
191d23b02eSJorge Ramirez-Ortiz
201d23b02eSJorge Ramirez-Ortiz static struct {
211d23b02eSJorge Ramirez-Ortiz uint8_t key[HW_UNIQUE_KEY_LENGTH];
221d23b02eSJorge Ramirez-Ortiz bool ready;
231d23b02eSJorge Ramirez-Ortiz } huk;
241d23b02eSJorge Ramirez-Ortiz
tee_zynqmp_get_device_dna(uint8_t * device_dna,size_t size)25*dfeed924SVesa Jääskeläinen __weak TEE_Result tee_zynqmp_get_device_dna(uint8_t *device_dna, size_t size)
26*dfeed924SVesa Jääskeläinen {
27*dfeed924SVesa Jääskeläinen if (size != ZYNQMP_EFUSE_LEN(DNA))
28*dfeed924SVesa Jääskeläinen return TEE_ERROR_BAD_PARAMETERS;
29*dfeed924SVesa Jääskeläinen
30*dfeed924SVesa Jääskeläinen /* Get Device DNA from the PS eFuses */
31*dfeed924SVesa Jääskeläinen return zynqmp_efuse_read(device_dna, size, DNA, false);
32*dfeed924SVesa Jääskeläinen }
33*dfeed924SVesa Jääskeläinen
34*dfeed924SVesa Jääskeläinen /*
35*dfeed924SVesa Jääskeläinen * Generate HUK source data
36*dfeed924SVesa Jääskeläinen *
37*dfeed924SVesa Jääskeläinen * Performs SHA256 over of data:
38*dfeed924SVesa Jääskeläinen * - Device DNA (from PL preferably)
39*dfeed924SVesa Jääskeläinen * - Selected user eFuses (HUK seed)
40*dfeed924SVesa Jääskeläinen *
41*dfeed924SVesa Jääskeläinen * HUK source data is later on AES encrypted with device key to shuffle source
42*dfeed924SVesa Jääskeläinen * data even further with secret key.
43*dfeed924SVesa Jääskeläinen *
44*dfeed924SVesa Jääskeläinen * Note: Even though the device key is secret used details for HUK source data
45*dfeed924SVesa Jääskeläinen * should not be exposed to REE environment.
46*dfeed924SVesa Jääskeläinen *
47*dfeed924SVesa Jääskeläinen * Note: You should not change HUK source data generation parameters after
48*dfeed924SVesa Jääskeläinen * devices have been deployed.
49*dfeed924SVesa Jääskeläinen *
50*dfeed924SVesa Jääskeläinen * @device_dna: Value of Device DNA
51*dfeed924SVesa Jääskeläinen * @device_dna_size: Size of Device DNA
52*dfeed924SVesa Jääskeläinen * @huk_source: Output buffer for HUK source data
53*dfeed924SVesa Jääskeläinen * @huk_source_size: Output buffer size for HUK source data
54*dfeed924SVesa Jääskeläinen * Return a TEE_Result compliant status
55*dfeed924SVesa Jääskeläinen */
tee_zynqmp_generate_huk_src(const uint8_t * device_dna,size_t device_dna_size,uint8_t * huk_source,size_t huk_source_size)56*dfeed924SVesa Jääskeläinen static TEE_Result tee_zynqmp_generate_huk_src(const uint8_t *device_dna,
57*dfeed924SVesa Jääskeläinen size_t device_dna_size,
58*dfeed924SVesa Jääskeläinen uint8_t *huk_source,
59*dfeed924SVesa Jääskeläinen size_t huk_source_size)
60*dfeed924SVesa Jääskeläinen {
61*dfeed924SVesa Jääskeläinen TEE_Result res = TEE_ERROR_GENERIC;
62*dfeed924SVesa Jääskeläinen uint32_t user_efuse = 0;
63*dfeed924SVesa Jääskeläinen void *ctx = NULL;
64*dfeed924SVesa Jääskeläinen int i = 0;
65*dfeed924SVesa Jääskeläinen
66*dfeed924SVesa Jääskeläinen assert(device_dna_size == ZYNQMP_EFUSE_LEN(DNA));
67*dfeed924SVesa Jääskeläinen assert(huk_source_size == HW_UNIQUE_KEY_LENGTH);
68*dfeed924SVesa Jääskeläinen
69*dfeed924SVesa Jääskeläinen res = crypto_hash_alloc_ctx(&ctx, TEE_ALG_SHA256);
70*dfeed924SVesa Jääskeläinen if (res)
71*dfeed924SVesa Jääskeläinen return res;
72*dfeed924SVesa Jääskeläinen
73*dfeed924SVesa Jääskeläinen res = crypto_hash_init(ctx);
74*dfeed924SVesa Jääskeläinen if (res)
75*dfeed924SVesa Jääskeläinen goto out;
76*dfeed924SVesa Jääskeläinen
77*dfeed924SVesa Jääskeläinen res = crypto_hash_update(ctx, device_dna, device_dna_size);
78*dfeed924SVesa Jääskeläinen if (res)
79*dfeed924SVesa Jääskeläinen goto out;
80*dfeed924SVesa Jääskeläinen
81*dfeed924SVesa Jääskeläinen /* Hash selected user eFuses */
82*dfeed924SVesa Jääskeläinen for (i = 0; i < (USER7 - USER0 + 1); i++) {
83*dfeed924SVesa Jääskeläinen if (CFG_ZYNQMP_HUK_USER_EFUSE_MASK & BIT(i)) {
84*dfeed924SVesa Jääskeläinen DMSG("Use User eFuse %d for HUK source data", i);
85*dfeed924SVesa Jääskeläinen
86*dfeed924SVesa Jääskeläinen res = zynqmp_efuse_read((uint8_t *)&user_efuse,
87*dfeed924SVesa Jääskeläinen sizeof(user_efuse), USER0 + i,
88*dfeed924SVesa Jääskeläinen false);
89*dfeed924SVesa Jääskeläinen if (res)
90*dfeed924SVesa Jääskeläinen goto out;
91*dfeed924SVesa Jääskeläinen
92*dfeed924SVesa Jääskeläinen res = crypto_hash_update(ctx, (uint8_t *)&user_efuse,
93*dfeed924SVesa Jääskeläinen sizeof(user_efuse));
94*dfeed924SVesa Jääskeläinen if (res)
95*dfeed924SVesa Jääskeläinen goto out;
96*dfeed924SVesa Jääskeläinen }
97*dfeed924SVesa Jääskeläinen }
98*dfeed924SVesa Jääskeläinen
99*dfeed924SVesa Jääskeläinen res = crypto_hash_final(ctx, huk_source, huk_source_size);
100*dfeed924SVesa Jääskeläinen out:
101*dfeed924SVesa Jääskeläinen crypto_hash_free_ctx(ctx);
102*dfeed924SVesa Jääskeläinen memzero_explicit(&user_efuse, sizeof(user_efuse));
103*dfeed924SVesa Jääskeläinen return res;
104*dfeed924SVesa Jääskeläinen }
105*dfeed924SVesa Jääskeläinen
tee_otp_get_hw_unique_key(struct tee_hw_unique_key * hwkey)1061d23b02eSJorge Ramirez-Ortiz TEE_Result tee_otp_get_hw_unique_key(struct tee_hw_unique_key *hwkey)
1071d23b02eSJorge Ramirez-Ortiz {
1081d23b02eSJorge Ramirez-Ortiz vaddr_t csu = core_mmu_get_va(CSU_BASE, MEM_AREA_IO_SEC, CSU_SIZE);
109*dfeed924SVesa Jääskeläinen uint8_t device_dna[ZYNQMP_EFUSE_LEN(DNA)] = { 0 };
1101d23b02eSJorge Ramirez-Ortiz uint8_t src[HW_UNIQUE_KEY_LENGTH] __aligned_csuaes = { 0 };
111*dfeed924SVesa Jääskeläinen uint8_t iv[ZYNQMP_GCM_IV_SIZE] = { 0 };
1121d23b02eSJorge Ramirez-Ortiz uint8_t tag[ZYNQMP_GCM_TAG_SIZE] __aligned_csuaes = { 0 };
1131d23b02eSJorge Ramirez-Ortiz uint8_t sha[HW_UNIQUE_KEY_LENGTH] = { 0 };
1141d23b02eSJorge Ramirez-Ortiz uint8_t dst[ZYNQMP_CSU_AES_DST_LEN(sizeof(src))]
1151d23b02eSJorge Ramirez-Ortiz __aligned_csuaes = { 0 };
1161d23b02eSJorge Ramirez-Ortiz TEE_Result ret = TEE_ERROR_GENERIC;
1171d23b02eSJorge Ramirez-Ortiz uint32_t status = 0;
1181d23b02eSJorge Ramirez-Ortiz
119*dfeed924SVesa Jääskeläinen static_assert(sizeof(device_dna) == ZYNQMP_GCM_IV_SIZE);
120*dfeed924SVesa Jääskeläinen
1211d23b02eSJorge Ramirez-Ortiz if (huk.ready)
1221d23b02eSJorge Ramirez-Ortiz goto out;
1231d23b02eSJorge Ramirez-Ortiz
124*dfeed924SVesa Jääskeläinen ret = tee_zynqmp_get_device_dna(device_dna, sizeof(device_dna));
1251d23b02eSJorge Ramirez-Ortiz if (ret) {
126*dfeed924SVesa Jääskeläinen EMSG("Can't read the Device DNA");
127*dfeed924SVesa Jääskeläinen goto cleanup;
1281d23b02eSJorge Ramirez-Ortiz }
1291d23b02eSJorge Ramirez-Ortiz
1301d23b02eSJorge Ramirez-Ortiz status = io_read32(csu + ZYNQMP_CSU_STATUS_OFFSET);
1311d23b02eSJorge Ramirez-Ortiz if (!(status & ZYNQMP_CSU_STATUS_AUTH)) {
1321d23b02eSJorge Ramirez-Ortiz /* The DNA is a unique identifier valid but not secure */
1331d23b02eSJorge Ramirez-Ortiz IMSG("CSU authentication disabled, using development HUK");
134*dfeed924SVesa Jääskeläinen
135*dfeed924SVesa Jääskeläinen /* Use hash of device DNA for development HUK */
136*dfeed924SVesa Jääskeläinen ret = tee_hash_createdigest(TEE_ALG_SHA256, device_dna,
137*dfeed924SVesa Jääskeläinen sizeof(device_dna), huk.key,
138*dfeed924SVesa Jääskeläinen sizeof(huk.key));
139*dfeed924SVesa Jääskeläinen if (ret) {
140*dfeed924SVesa Jääskeläinen EMSG("Can't generate the SHA256 for the DNA eFuse");
141*dfeed924SVesa Jääskeläinen goto cleanup;
142*dfeed924SVesa Jääskeläinen }
143*dfeed924SVesa Jääskeläinen
1441d23b02eSJorge Ramirez-Ortiz huk.ready = true;
1451d23b02eSJorge Ramirez-Ortiz goto out;
1461d23b02eSJorge Ramirez-Ortiz }
1471d23b02eSJorge Ramirez-Ortiz
148*dfeed924SVesa Jääskeläinen /* Use device DNA for IV */
149*dfeed924SVesa Jääskeläinen memcpy(iv, device_dna, sizeof(device_dna));
150*dfeed924SVesa Jääskeläinen
151*dfeed924SVesa Jääskeläinen /* Generate HUK source data */
152*dfeed924SVesa Jääskeläinen ret = tee_zynqmp_generate_huk_src(device_dna, sizeof(device_dna), src,
153*dfeed924SVesa Jääskeläinen sizeof(src));
154*dfeed924SVesa Jääskeläinen if (ret) {
155*dfeed924SVesa Jääskeläinen EMSG("Failed to generate HUK source data");
156*dfeed924SVesa Jääskeläinen goto cleanup;
157*dfeed924SVesa Jääskeläinen }
158*dfeed924SVesa Jääskeläinen
159*dfeed924SVesa Jääskeläinen #ifdef CFG_ZYNQMP_CSU_PUF
1601d23b02eSJorge Ramirez-Ortiz /*
1611d23b02eSJorge Ramirez-Ortiz * Neither the PMUFW nor the PUF hardware provide an indication of the
1621d23b02eSJorge Ramirez-Ortiz * PUF KEK registration status. The verification algorithm that follows
1631d23b02eSJorge Ramirez-Ortiz * encrypts and then decrypts the resulting string regenerating the
1641d23b02eSJorge Ramirez-Ortiz * PUF KEK in between: if the outputs match, then the PUF KEK was
1651d23b02eSJorge Ramirez-Ortiz * registered properly and we can use it to generate the HUK.
1661d23b02eSJorge Ramirez-Ortiz */
1671d23b02eSJorge Ramirez-Ortiz zynqmp_csu_puf_reset();
1681d23b02eSJorge Ramirez-Ortiz
1691d23b02eSJorge Ramirez-Ortiz ret = zynqmp_csu_puf_regenerate();
1701d23b02eSJorge Ramirez-Ortiz if (ret) {
1711d23b02eSJorge Ramirez-Ortiz EMSG("PUF regeneration error");
172*dfeed924SVesa Jääskeläinen goto cleanup;
1731d23b02eSJorge Ramirez-Ortiz }
174*dfeed924SVesa Jääskeläinen #endif
1751d23b02eSJorge Ramirez-Ortiz
1761d23b02eSJorge Ramirez-Ortiz memcpy(sha, src, sizeof(sha));
1771d23b02eSJorge Ramirez-Ortiz /* The dst buffer must be large enough to include the generated tag */
1781d23b02eSJorge Ramirez-Ortiz ret = zynqmp_csu_aes_encrypt_data(src, sizeof(src), dst, sizeof(dst),
179*dfeed924SVesa Jääskeläinen tag, sizeof(tag), iv, sizeof(iv),
1801d23b02eSJorge Ramirez-Ortiz ZYNQMP_CSU_AES_KEY_SRC_DEV);
1811d23b02eSJorge Ramirez-Ortiz if (ret) {
1821d23b02eSJorge Ramirez-Ortiz EMSG("Can't encrypt DNA, please make sure PUF was registered");
183*dfeed924SVesa Jääskeläinen goto cleanup;
1841d23b02eSJorge Ramirez-Ortiz }
1851d23b02eSJorge Ramirez-Ortiz
186*dfeed924SVesa Jääskeläinen #ifdef CFG_ZYNQMP_CSU_PUF
1871d23b02eSJorge Ramirez-Ortiz /* regenerate the PUF KEK */
1881d23b02eSJorge Ramirez-Ortiz ret = zynqmp_csu_puf_regenerate();
1891d23b02eSJorge Ramirez-Ortiz if (ret) {
1901d23b02eSJorge Ramirez-Ortiz EMSG("PUF regeneration error");
191*dfeed924SVesa Jääskeläinen goto cleanup;
1921d23b02eSJorge Ramirez-Ortiz }
193*dfeed924SVesa Jääskeläinen #endif
1941d23b02eSJorge Ramirez-Ortiz memset(src, 0, sizeof(src));
1951d23b02eSJorge Ramirez-Ortiz /* Ignore the tag data from the dst buffer - pass a smaller size */
1961d23b02eSJorge Ramirez-Ortiz ret = zynqmp_csu_aes_decrypt_data(dst, sizeof(src), src, sizeof(src),
1971d23b02eSJorge Ramirez-Ortiz tag, sizeof(tag), iv,
1981d23b02eSJorge Ramirez-Ortiz ZYNQMP_EFUSE_LEN(DNA),
1991d23b02eSJorge Ramirez-Ortiz ZYNQMP_CSU_AES_KEY_SRC_DEV);
2001d23b02eSJorge Ramirez-Ortiz if (ret) {
2011d23b02eSJorge Ramirez-Ortiz EMSG("Can't decrypt DNA, please make sure PUF was registered");
202*dfeed924SVesa Jääskeläinen goto cleanup;
2031d23b02eSJorge Ramirez-Ortiz }
2041d23b02eSJorge Ramirez-Ortiz
2051d23b02eSJorge Ramirez-Ortiz if (memcmp(src, sha, sizeof(sha))) {
2061d23b02eSJorge Ramirez-Ortiz EMSG("PUF not ready, can't create HUK");
207*dfeed924SVesa Jääskeläinen ret = TEE_ERROR_GENERIC;
208*dfeed924SVesa Jääskeläinen goto cleanup;
2091d23b02eSJorge Ramirez-Ortiz }
2101d23b02eSJorge Ramirez-Ortiz
2111d23b02eSJorge Ramirez-Ortiz IMSG("HUK ready");
212*dfeed924SVesa Jääskeläinen
2131d23b02eSJorge Ramirez-Ortiz /*
214*dfeed924SVesa Jääskeläinen * The HUK is the SHA-256 of Device DNA with optional User eFuses
215*dfeed924SVesa Jääskeläinen * included and then AES-GCM encrypted with the selected Device Key
216*dfeed924SVesa Jääskeläinen * using the Device DNA as the IV.
2171d23b02eSJorge Ramirez-Ortiz */
2181d23b02eSJorge Ramirez-Ortiz memcpy(huk.key, dst, sizeof(huk.key));
2191d23b02eSJorge Ramirez-Ortiz huk.ready = true;
2201d23b02eSJorge Ramirez-Ortiz out:
2211d23b02eSJorge Ramirez-Ortiz memcpy(hwkey->data, huk.key, HW_UNIQUE_KEY_LENGTH);
222*dfeed924SVesa Jääskeläinen ret = TEE_SUCCESS;
2231d23b02eSJorge Ramirez-Ortiz
224*dfeed924SVesa Jääskeläinen cleanup:
225*dfeed924SVesa Jääskeläinen /* Cleanup stack memory so that there are no left overs */
226*dfeed924SVesa Jääskeläinen memzero_explicit(dst, sizeof(dst));
227*dfeed924SVesa Jääskeläinen memzero_explicit(sha, sizeof(sha));
228*dfeed924SVesa Jääskeläinen memzero_explicit(tag, sizeof(tag));
229*dfeed924SVesa Jääskeläinen memzero_explicit(iv, sizeof(iv));
230*dfeed924SVesa Jääskeläinen memzero_explicit(src, sizeof(src));
231*dfeed924SVesa Jääskeläinen memzero_explicit(device_dna, sizeof(device_dna));
232*dfeed924SVesa Jääskeläinen
233*dfeed924SVesa Jääskeläinen return ret;
2341d23b02eSJorge Ramirez-Ortiz }
235