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
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)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, in_key, in_key_size);
56 if (res != TEE_SUCCESS)
57 goto exit;
58
59 res = crypto_mac_update(ctx, message, message_size);
60 if (res != TEE_SUCCESS)
61 goto exit;
62
63 res = crypto_mac_final(ctx, 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);
71 return res;
72 }
73
tee_fs_fek_crypt(const TEE_UUID * uuid,TEE_OperationMode mode,const uint8_t * in_key,size_t size,uint8_t * out_key)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, mode, tsk, sizeof(tsk), NULL, 0, NULL, 0);
115 if (res != TEE_SUCCESS)
116 goto exit;
117
118 res = crypto_cipher_update(ctx, mode, true, in_key, size, dst_key);
119 if (res != TEE_SUCCESS)
120 goto exit;
121
122 crypto_cipher_final(ctx);
123
124 memcpy(out_key, dst_key, sizeof(dst_key));
125
126 exit:
127 crypto_cipher_free_ctx(ctx);
128 memzero_explicit(tsk, sizeof(tsk));
129 memzero_explicit(dst_key, sizeof(dst_key));
130
131 return res;
132 }
133
generate_fek(uint8_t * key,uint8_t len)134 static TEE_Result generate_fek(uint8_t *key, uint8_t len)
135 {
136 return crypto_rng_read(key, len);
137 }
138
tee_fs_init_key_manager(void)139 static TEE_Result tee_fs_init_key_manager(void)
140 {
141 TEE_Result res = TEE_SUCCESS;
142
143 COMPILE_TIME_ASSERT(TEE_FS_KM_SSK_SIZE <= HUK_SUBKEY_MAX_LEN);
144
145 res = huk_subkey_derive(HUK_SUBKEY_SSK, NULL, 0,
146 tee_fs_ssk.key, sizeof(tee_fs_ssk.key));
147 if (res == TEE_SUCCESS)
148 tee_fs_ssk.is_init = 1;
149 else
150 memzero_explicit(&tee_fs_ssk, sizeof(tee_fs_ssk));
151
152 return res;
153 }
154
tee_fs_generate_fek(const TEE_UUID * uuid,void * buf,size_t buf_size)155 TEE_Result tee_fs_generate_fek(const TEE_UUID *uuid, void *buf, size_t buf_size)
156 {
157 TEE_Result res;
158
159 if (buf_size != TEE_FS_KM_FEK_SIZE)
160 return TEE_ERROR_BAD_PARAMETERS;
161
162 res = generate_fek(buf, TEE_FS_KM_FEK_SIZE);
163 if (res != TEE_SUCCESS)
164 return res;
165
166 return tee_fs_fek_crypt(uuid, TEE_MODE_ENCRYPT, buf,
167 TEE_FS_KM_FEK_SIZE, buf);
168 }
169
sha256(uint8_t * out,size_t out_size,const uint8_t * in,size_t in_size)170 static TEE_Result sha256(uint8_t *out, size_t out_size, const uint8_t *in,
171 size_t in_size)
172 {
173 return tee_hash_createdigest(TEE_ALG_SHA256, in, in_size,
174 out, out_size);
175 }
176
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)177 static TEE_Result aes_ecb(uint8_t out[TEE_AES_BLOCK_SIZE],
178 const uint8_t in[TEE_AES_BLOCK_SIZE],
179 const uint8_t *key, size_t key_size)
180 {
181 TEE_Result res;
182 void *ctx = NULL;
183
184 res = crypto_cipher_alloc_ctx(&ctx, TEE_ALG_AES_ECB_NOPAD);
185 if (res != TEE_SUCCESS)
186 return res;
187
188 res = crypto_cipher_init(ctx, TEE_MODE_ENCRYPT, key,
189 key_size, NULL, 0, NULL, 0);
190 if (res != TEE_SUCCESS)
191 goto out;
192
193 res = crypto_cipher_update(ctx, TEE_MODE_ENCRYPT, true, in,
194 TEE_AES_BLOCK_SIZE, out);
195 if (res != TEE_SUCCESS)
196 goto out;
197
198 crypto_cipher_final(ctx);
199 res = TEE_SUCCESS;
200
201 out:
202 crypto_cipher_free_ctx(ctx);
203 return res;
204 }
205
essiv(uint8_t iv[TEE_AES_BLOCK_SIZE],const uint8_t fek[TEE_FS_KM_FEK_SIZE],uint16_t blk_idx)206 static TEE_Result essiv(uint8_t iv[TEE_AES_BLOCK_SIZE],
207 const uint8_t fek[TEE_FS_KM_FEK_SIZE],
208 uint16_t blk_idx)
209 {
210 TEE_Result res;
211 uint8_t sha[TEE_SHA256_HASH_SIZE];
212 uint8_t pad_blkid[TEE_AES_BLOCK_SIZE] = { 0, };
213
214 res = sha256(sha, sizeof(sha), fek, TEE_FS_KM_FEK_SIZE);
215 if (res != TEE_SUCCESS)
216 return res;
217
218 pad_blkid[0] = (blk_idx & 0xFF);
219 pad_blkid[1] = (blk_idx & 0xFF00) >> 8;
220
221 res = aes_ecb(iv, pad_blkid, sha, 16);
222
223 memzero_explicit(sha, sizeof(sha));
224 return res;
225 }
226
227 /*
228 * Encryption/decryption of RPMB FS file data. This is AES CBC with ESSIV.
229 */
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)230 TEE_Result tee_fs_crypt_block(const TEE_UUID *uuid, uint8_t *out,
231 const uint8_t *in, size_t size,
232 uint16_t blk_idx, const uint8_t *encrypted_fek,
233 TEE_OperationMode mode)
234 {
235 TEE_Result res;
236 uint8_t fek[TEE_FS_KM_FEK_SIZE];
237 uint8_t iv[TEE_AES_BLOCK_SIZE];
238 void *ctx;
239
240 DMSG("%scrypt block #%u", (mode == TEE_MODE_ENCRYPT) ? "En" : "De",
241 blk_idx);
242
243 /* Decrypt FEK */
244 res = tee_fs_fek_crypt(uuid, TEE_MODE_DECRYPT, encrypted_fek,
245 TEE_FS_KM_FEK_SIZE, fek);
246 if (res != TEE_SUCCESS)
247 goto wipe;
248
249 /* Compute initialization vector for this block */
250 res = essiv(iv, fek, blk_idx);
251 if (res != TEE_SUCCESS)
252 goto wipe;
253
254 /* Run AES CBC */
255 res = crypto_cipher_alloc_ctx(&ctx, TEE_ALG_AES_CBC_NOPAD);
256 if (res != TEE_SUCCESS)
257 goto wipe;
258
259 res = crypto_cipher_init(ctx, mode, fek, sizeof(fek), NULL,
260 0, iv, TEE_AES_BLOCK_SIZE);
261 if (res != TEE_SUCCESS)
262 goto exit;
263 res = crypto_cipher_update(ctx, mode, true, in, size, out);
264 if (res != TEE_SUCCESS)
265 goto exit;
266
267 crypto_cipher_final(ctx);
268
269 exit:
270 crypto_cipher_free_ctx(ctx);
271 wipe:
272 memzero_explicit(fek, sizeof(fek));
273 memzero_explicit(iv, sizeof(iv));
274 return res;
275 }
276
277 service_init_late(tee_fs_init_key_manager);
278