xref: /optee_os/core/drivers/zynqmp_huk.c (revision dfeed9241800a4263bc76ee3a2fb8edae2c1498a)
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