xref: /optee_os/core/tee/tee_fs_key_manager.c (revision 8bbd9b374a51a1b8617796aae8a70c271543357f)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2015, Linaro Limited
4  */
5 
6 
7 /*
8  * Acronyms:
9  *
10  * FEK - File Encryption Key
11  * SSK - Secure Storage Key
12  * TSK - Trusted app Storage Key
13  * IV  - Initial vector
14  * HUK - Hardware Unique Key
15  * RNG - Random Number Generator
16  */
17 
18 #include <assert.h>
19 #include <compiler.h>
20 #include <crypto/crypto.h>
21 #include <initcall.h>
22 #include <kernel/huk_subkey.h>
23 #include <kernel/panic.h>
24 #include <kernel/tee_common_otp.h>
25 #include <kernel/tee_ta_manager.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <string_ext.h>
29 #include <tee/tee_cryp_utl.h>
30 #include <tee/tee_fs_key_manager.h>
31 #include <trace.h>
32 #include <util.h>
33 
34 struct tee_fs_ssk {
35 	bool is_init;
36 	uint8_t key[TEE_FS_KM_SSK_SIZE];
37 };
38 
39 static struct tee_fs_ssk tee_fs_ssk;
40 
41 static TEE_Result do_hmac(void *out_key, size_t out_key_size,
42 			  const void *in_key, size_t in_key_size,
43 			  const void *message, size_t message_size)
44 {
45 	TEE_Result res;
46 	void *ctx = NULL;
47 
48 	if (!out_key || !in_key || !message)
49 		return TEE_ERROR_BAD_PARAMETERS;
50 
51 	res = crypto_mac_alloc_ctx(&ctx, TEE_FS_KM_HMAC_ALG);
52 	if (res != TEE_SUCCESS)
53 		return res;
54 
55 	res = crypto_mac_init(ctx, TEE_FS_KM_HMAC_ALG, in_key, in_key_size);
56 	if (res != TEE_SUCCESS)
57 		goto exit;
58 
59 	res = crypto_mac_update(ctx, TEE_FS_KM_HMAC_ALG, message, message_size);
60 	if (res != TEE_SUCCESS)
61 		goto exit;
62 
63 	res = crypto_mac_final(ctx, TEE_FS_KM_HMAC_ALG, out_key, out_key_size);
64 	if (res != TEE_SUCCESS)
65 		goto exit;
66 
67 	res = TEE_SUCCESS;
68 
69 exit:
70 	crypto_mac_free_ctx(ctx, TEE_FS_KM_HMAC_ALG);
71 	return res;
72 }
73 
74 TEE_Result tee_fs_fek_crypt(const TEE_UUID *uuid, TEE_OperationMode mode,
75 			    const uint8_t *in_key, size_t size,
76 			    uint8_t *out_key)
77 {
78 	TEE_Result res;
79 	void *ctx = NULL;
80 	uint8_t tsk[TEE_FS_KM_TSK_SIZE];
81 	uint8_t dst_key[size];
82 
83 	if (!in_key || !out_key)
84 		return TEE_ERROR_BAD_PARAMETERS;
85 
86 	if (size != TEE_FS_KM_FEK_SIZE)
87 		return TEE_ERROR_BAD_PARAMETERS;
88 
89 	if (tee_fs_ssk.is_init == 0)
90 		return TEE_ERROR_GENERIC;
91 
92 	if (uuid) {
93 		res = do_hmac(tsk, sizeof(tsk), tee_fs_ssk.key,
94 			      TEE_FS_KM_SSK_SIZE, uuid, sizeof(*uuid));
95 		if (res != TEE_SUCCESS)
96 			return res;
97 	} else {
98 		/*
99 		 * Pick something of a different size than TEE_UUID to
100 		 * guarantee that there's never a conflict.
101 		 */
102 		uint8_t dummy[1] = { 0 };
103 
104 		res = do_hmac(tsk, sizeof(tsk), tee_fs_ssk.key,
105 			      TEE_FS_KM_SSK_SIZE, dummy, sizeof(dummy));
106 		if (res != TEE_SUCCESS)
107 			return res;
108 	}
109 
110 	res = crypto_cipher_alloc_ctx(&ctx, TEE_FS_KM_ENC_FEK_ALG);
111 	if (res != TEE_SUCCESS)
112 		return res;
113 
114 	res = crypto_cipher_init(ctx, TEE_FS_KM_ENC_FEK_ALG, mode, tsk,
115 				 sizeof(tsk), NULL, 0, NULL, 0);
116 	if (res != TEE_SUCCESS)
117 		goto exit;
118 
119 	res = crypto_cipher_update(ctx, TEE_FS_KM_ENC_FEK_ALG,
120 				   mode, true, in_key, size, dst_key);
121 	if (res != TEE_SUCCESS)
122 		goto exit;
123 
124 	crypto_cipher_final(ctx, TEE_FS_KM_ENC_FEK_ALG);
125 
126 	memcpy(out_key, dst_key, sizeof(dst_key));
127 
128 exit:
129 	crypto_cipher_free_ctx(ctx, TEE_FS_KM_ENC_FEK_ALG);
130 	memzero_explicit(tsk, sizeof(tsk));
131 	memzero_explicit(dst_key, sizeof(dst_key));
132 
133 	return res;
134 }
135 
136 static TEE_Result generate_fek(uint8_t *key, uint8_t len)
137 {
138 	return crypto_rng_read(key, len);
139 }
140 
141 static TEE_Result tee_fs_init_key_manager(void)
142 {
143 	TEE_Result res = TEE_SUCCESS;
144 
145 	COMPILE_TIME_ASSERT(TEE_FS_KM_SSK_SIZE <= HUK_SUBKEY_MAX_LEN);
146 
147 	res = huk_subkey_derive(HUK_SUBKEY_SSK, NULL, 0,
148 				tee_fs_ssk.key, sizeof(tee_fs_ssk.key));
149 	if (res == TEE_SUCCESS)
150 		tee_fs_ssk.is_init = 1;
151 	else
152 		memzero_explicit(&tee_fs_ssk, sizeof(tee_fs_ssk));
153 
154 	return res;
155 }
156 
157 TEE_Result tee_fs_generate_fek(const TEE_UUID *uuid, void *buf, size_t buf_size)
158 {
159 	TEE_Result res;
160 
161 	if (buf_size != TEE_FS_KM_FEK_SIZE)
162 		return TEE_ERROR_BAD_PARAMETERS;
163 
164 	res = generate_fek(buf, TEE_FS_KM_FEK_SIZE);
165 	if (res != TEE_SUCCESS)
166 		return res;
167 
168 	return tee_fs_fek_crypt(uuid, TEE_MODE_ENCRYPT, buf,
169 				TEE_FS_KM_FEK_SIZE, buf);
170 }
171 
172 static TEE_Result sha256(uint8_t *out, size_t out_size, const uint8_t *in,
173 			 size_t in_size)
174 {
175 	return tee_hash_createdigest(TEE_ALG_SHA256, in, in_size,
176 				     out, out_size);
177 }
178 
179 static TEE_Result aes_ecb(uint8_t out[TEE_AES_BLOCK_SIZE],
180 			  const uint8_t in[TEE_AES_BLOCK_SIZE],
181 			  const uint8_t *key, size_t key_size)
182 {
183 	TEE_Result res;
184 	void *ctx = NULL;
185 	const uint32_t algo = TEE_ALG_AES_ECB_NOPAD;
186 
187 	res = crypto_cipher_alloc_ctx(&ctx, algo);
188 	if (res != TEE_SUCCESS)
189 		return res;
190 
191 	res = crypto_cipher_init(ctx, algo, TEE_MODE_ENCRYPT, key,
192 				 key_size, NULL, 0, NULL, 0);
193 	if (res != TEE_SUCCESS)
194 		goto out;
195 
196 	res = crypto_cipher_update(ctx, algo, TEE_MODE_ENCRYPT, true, in,
197 				   TEE_AES_BLOCK_SIZE, out);
198 	if (res != TEE_SUCCESS)
199 		goto out;
200 
201 	crypto_cipher_final(ctx, algo);
202 	res = TEE_SUCCESS;
203 
204 out:
205 	crypto_cipher_free_ctx(ctx, algo);
206 	return res;
207 }
208 
209 static TEE_Result essiv(uint8_t iv[TEE_AES_BLOCK_SIZE],
210 			const uint8_t fek[TEE_FS_KM_FEK_SIZE],
211 			uint16_t blk_idx)
212 {
213 	TEE_Result res;
214 	uint8_t sha[TEE_SHA256_HASH_SIZE];
215 	uint8_t pad_blkid[TEE_AES_BLOCK_SIZE] = { 0, };
216 
217 	res = sha256(sha, sizeof(sha), fek, TEE_FS_KM_FEK_SIZE);
218 	if (res != TEE_SUCCESS)
219 		return res;
220 
221 	pad_blkid[0] = (blk_idx & 0xFF);
222 	pad_blkid[1] = (blk_idx & 0xFF00) >> 8;
223 
224 	res = aes_ecb(iv, pad_blkid, sha, 16);
225 
226 	memzero_explicit(sha, sizeof(sha));
227 	return res;
228 }
229 
230 /*
231  * Encryption/decryption of RPMB FS file data. This is AES CBC with ESSIV.
232  */
233 TEE_Result tee_fs_crypt_block(const TEE_UUID *uuid, uint8_t *out,
234 			      const uint8_t *in, size_t size,
235 			      uint16_t blk_idx, const uint8_t *encrypted_fek,
236 			      TEE_OperationMode mode)
237 {
238 	TEE_Result res;
239 	uint8_t fek[TEE_FS_KM_FEK_SIZE];
240 	uint8_t iv[TEE_AES_BLOCK_SIZE];
241 	void *ctx;
242 	const uint32_t algo = TEE_ALG_AES_CBC_NOPAD;
243 
244 	DMSG("%scrypt block #%u", (mode == TEE_MODE_ENCRYPT) ? "En" : "De",
245 	     blk_idx);
246 
247 	/* Decrypt FEK */
248 	res = tee_fs_fek_crypt(uuid, TEE_MODE_DECRYPT, encrypted_fek,
249 			       TEE_FS_KM_FEK_SIZE, fek);
250 	if (res != TEE_SUCCESS)
251 		goto wipe;
252 
253 	/* Compute initialization vector for this block */
254 	res = essiv(iv, fek, blk_idx);
255 	if (res != TEE_SUCCESS)
256 		goto wipe;
257 
258 	/* Run AES CBC */
259 	res = crypto_cipher_alloc_ctx(&ctx, algo);
260 	if (res != TEE_SUCCESS)
261 		goto wipe;
262 
263 	res = crypto_cipher_init(ctx, algo, mode, fek, sizeof(fek), NULL,
264 				 0, iv, TEE_AES_BLOCK_SIZE);
265 	if (res != TEE_SUCCESS)
266 		goto exit;
267 	res = crypto_cipher_update(ctx, algo, mode, true, in, size, out);
268 	if (res != TEE_SUCCESS)
269 		goto exit;
270 
271 	crypto_cipher_final(ctx, algo);
272 
273 exit:
274 	crypto_cipher_free_ctx(ctx, algo);
275 wipe:
276 	memzero_explicit(fek, sizeof(fek));
277 	memzero_explicit(iv, sizeof(iv));
278 	return res;
279 }
280 
281 service_init_late(tee_fs_init_key_manager);
282