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