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