1 /*
2 * Copyright (c) 2017, Linaro Limited
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27 #include <inttypes.h>
28
29 #include <tee_internal_api.h>
30 #include <tee_internal_api_extensions.h>
31
32 #include <aes_ta.h>
33
34 #define AES128_KEY_BIT_SIZE 128
35 #define AES128_KEY_BYTE_SIZE (AES128_KEY_BIT_SIZE / 8)
36 #define AES256_KEY_BIT_SIZE 256
37 #define AES256_KEY_BYTE_SIZE (AES256_KEY_BIT_SIZE / 8)
38
39 /*
40 * Ciphering context: each opened session relates to a cipehring operation.
41 * - configure the AES flavour from a command.
42 * - load key from a command (here the key is provided by the REE)
43 * - reset init vector (here IV is provided by the REE)
44 * - cipher a buffer frame (here input and output buffers are non-secure)
45 */
46 struct aes_cipher {
47 uint32_t algo; /* AES flavour */
48 uint32_t mode; /* Encode or decode */
49 uint32_t key_size; /* AES key size in byte */
50 TEE_OperationHandle op_handle; /* AES ciphering operation */
51 TEE_ObjectHandle key_handle; /* transient object to load the key */
52 };
53
54 /*
55 * Few routines to convert IDs from TA API into IDs from OP-TEE.
56 */
ta2tee_algo_id(uint32_t param,uint32_t * algo)57 static TEE_Result ta2tee_algo_id(uint32_t param, uint32_t *algo)
58 {
59 switch (param) {
60 case TA_AES_ALGO_ECB:
61 *algo = TEE_ALG_AES_ECB_NOPAD;
62 return TEE_SUCCESS;
63 case TA_AES_ALGO_CBC:
64 *algo = TEE_ALG_AES_CBC_NOPAD;
65 return TEE_SUCCESS;
66 case TA_AES_ALGO_CTR:
67 *algo = TEE_ALG_AES_CTR;
68 return TEE_SUCCESS;
69 default:
70 EMSG("Invalid algo %u", param);
71 return TEE_ERROR_BAD_PARAMETERS;
72 }
73 }
ta2tee_key_size(uint32_t param,uint32_t * key_size)74 static TEE_Result ta2tee_key_size(uint32_t param, uint32_t *key_size)
75 {
76 switch (param) {
77 case AES128_KEY_BYTE_SIZE:
78 case AES256_KEY_BYTE_SIZE:
79 *key_size = param;
80 return TEE_SUCCESS;
81 default:
82 EMSG("Invalid key size %u", param);
83 return TEE_ERROR_BAD_PARAMETERS;
84 }
85 }
ta2tee_mode_id(uint32_t param,uint32_t * mode)86 static TEE_Result ta2tee_mode_id(uint32_t param, uint32_t *mode)
87 {
88 switch (param) {
89 case TA_AES_MODE_ENCODE:
90 *mode = TEE_MODE_ENCRYPT;
91 return TEE_SUCCESS;
92 case TA_AES_MODE_DECODE:
93 *mode = TEE_MODE_DECRYPT;
94 return TEE_SUCCESS;
95 default:
96 EMSG("Invalid mode %u", param);
97 return TEE_ERROR_BAD_PARAMETERS;
98 }
99 }
100
101 /*
102 * Process command TA_AES_CMD_PREPARE. API in aes_ta.h
103 *
104 * Allocate resources required for the ciphering operation.
105 * During ciphering operation, when expect client can:
106 * - update the key materials (provided by client)
107 * - reset the initial vector (provided by client)
108 * - cipher an input buffer into an output buffer (provided by client)
109 */
alloc_resources(void * session,uint32_t param_types,TEE_Param params[4])110 static TEE_Result alloc_resources(void *session, uint32_t param_types,
111 TEE_Param params[4])
112 {
113 const uint32_t exp_param_types =
114 TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
115 TEE_PARAM_TYPE_VALUE_INPUT,
116 TEE_PARAM_TYPE_VALUE_INPUT,
117 TEE_PARAM_TYPE_NONE);
118 struct aes_cipher *sess;
119 TEE_Attribute attr;
120 TEE_Result res;
121 char *key;
122
123 /* Get ciphering context from session ID */
124 DMSG("Session %p: get ciphering resources", session);
125 sess = (struct aes_cipher *)session;
126
127 /* Safely get the invocation parameters */
128 if (param_types != exp_param_types)
129 return TEE_ERROR_BAD_PARAMETERS;
130
131 res = ta2tee_algo_id(params[0].value.a, &sess->algo);
132 if (res != TEE_SUCCESS)
133 return res;
134
135 res = ta2tee_key_size(params[1].value.a, &sess->key_size);
136 if (res != TEE_SUCCESS)
137 return res;
138
139 res = ta2tee_mode_id(params[2].value.a, &sess->mode);
140 if (res != TEE_SUCCESS)
141 return res;
142
143 /*
144 * Ready to allocate the resources which are:
145 * - an operation handle, for an AES ciphering of given configuration
146 * - a transient object that will be use to load the key materials
147 * into the AES ciphering operation.
148 */
149
150 /* Free potential previous operation */
151 if (sess->op_handle != TEE_HANDLE_NULL)
152 TEE_FreeOperation(sess->op_handle);
153
154 /* Allocate operation: AES/CTR, mode and size from params */
155 res = TEE_AllocateOperation(&sess->op_handle,
156 sess->algo,
157 sess->mode,
158 sess->key_size * 8);
159 if (res != TEE_SUCCESS) {
160 EMSG("Failed to allocate operation");
161 sess->op_handle = TEE_HANDLE_NULL;
162 goto err;
163 }
164
165 /* Free potential previous transient object */
166 if (sess->key_handle != TEE_HANDLE_NULL)
167 TEE_FreeTransientObject(sess->key_handle);
168
169 /* Allocate transient object according to target key size */
170 res = TEE_AllocateTransientObject(TEE_TYPE_AES,
171 sess->key_size * 8,
172 &sess->key_handle);
173 if (res != TEE_SUCCESS) {
174 EMSG("Failed to allocate transient object");
175 sess->key_handle = TEE_HANDLE_NULL;
176 goto err;
177 }
178
179 /*
180 * When loading a key in the cipher session, set_aes_key()
181 * will reset the operation and load a key. But we cannot
182 * reset and operation that has no key yet (GPD TEE Internal
183 * Core API Specification – Public Release v1.1.1, section
184 * 6.2.5 TEE_ResetOperation). In consequence, we will load a
185 * dummy key in the operation so that operation can be reset
186 * when updating the key.
187 */
188 key = TEE_Malloc(sess->key_size, 0);
189 if (!key) {
190 res = TEE_ERROR_OUT_OF_MEMORY;
191 goto err;
192 }
193
194 TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, key, sess->key_size);
195
196 res = TEE_PopulateTransientObject(sess->key_handle, &attr, 1);
197 if (res != TEE_SUCCESS) {
198 EMSG("TEE_PopulateTransientObject failed, %x", res);
199 goto err;
200 }
201
202 res = TEE_SetOperationKey(sess->op_handle, sess->key_handle);
203 if (res != TEE_SUCCESS) {
204 EMSG("TEE_SetOperationKey failed %x", res);
205 goto err;
206 }
207
208 return res;
209
210 err:
211 if (sess->op_handle != TEE_HANDLE_NULL)
212 TEE_FreeOperation(sess->op_handle);
213 sess->op_handle = TEE_HANDLE_NULL;
214
215 if (sess->key_handle != TEE_HANDLE_NULL)
216 TEE_FreeTransientObject(sess->key_handle);
217 sess->key_handle = TEE_HANDLE_NULL;
218
219 return res;
220 }
221
222 /*
223 * Process command TA_AES_CMD_SET_KEY. API in aes_ta.h
224 */
set_aes_key(void * session,uint32_t param_types,TEE_Param params[4])225 static TEE_Result set_aes_key(void *session, uint32_t param_types,
226 TEE_Param params[4])
227 {
228 const uint32_t exp_param_types =
229 TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
230 TEE_PARAM_TYPE_NONE,
231 TEE_PARAM_TYPE_NONE,
232 TEE_PARAM_TYPE_NONE);
233 struct aes_cipher *sess;
234 TEE_Attribute attr;
235 TEE_Result res;
236 uint32_t key_sz;
237 char *key;
238
239 /* Get ciphering context from session ID */
240 DMSG("Session %p: load key material", session);
241 sess = (struct aes_cipher *)session;
242
243 /* Safely get the invocation parameters */
244 if (param_types != exp_param_types)
245 return TEE_ERROR_BAD_PARAMETERS;
246
247 key = params[0].memref.buffer;
248 key_sz = params[0].memref.size;
249
250 if (key_sz != sess->key_size) {
251 EMSG("Wrong key size %" PRIu32 ", expect %" PRIu32 " bytes",
252 key_sz, sess->key_size);
253 return TEE_ERROR_BAD_PARAMETERS;
254 }
255
256 /*
257 * Load the key material into the configured operation
258 * - create a secret key attribute with the key material
259 * TEE_InitRefAttribute()
260 * - reset transient object and load attribute data
261 * TEE_ResetTransientObject()
262 * TEE_PopulateTransientObject()
263 * - load the key (transient object) into the ciphering operation
264 * TEE_SetOperationKey()
265 *
266 * TEE_SetOperationKey() requires operation to be in "initial state".
267 * We can use TEE_ResetOperation() to reset the operation but this
268 * API cannot be used on operation with key(s) not yet set. Hence,
269 * when allocating the operation handle, we load a dummy key.
270 * Thus, set_key sequence always reset then set key on operation.
271 */
272
273 TEE_InitRefAttribute(&attr, TEE_ATTR_SECRET_VALUE, key, key_sz);
274
275 TEE_ResetTransientObject(sess->key_handle);
276 res = TEE_PopulateTransientObject(sess->key_handle, &attr, 1);
277 if (res != TEE_SUCCESS) {
278 EMSG("TEE_PopulateTransientObject failed, %x", res);
279 return res;
280 }
281
282 TEE_ResetOperation(sess->op_handle);
283 res = TEE_SetOperationKey(sess->op_handle, sess->key_handle);
284 if (res != TEE_SUCCESS) {
285 EMSG("TEE_SetOperationKey failed %x", res);
286 return res;
287 }
288
289 return res;
290 }
291
292 /*
293 * Process command TA_AES_CMD_SET_IV. API in aes_ta.h
294 */
reset_aes_iv(void * session,uint32_t param_types,TEE_Param params[4])295 static TEE_Result reset_aes_iv(void *session, uint32_t param_types,
296 TEE_Param params[4])
297 {
298 const uint32_t exp_param_types =
299 TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
300 TEE_PARAM_TYPE_NONE,
301 TEE_PARAM_TYPE_NONE,
302 TEE_PARAM_TYPE_NONE);
303 struct aes_cipher *sess;
304 size_t iv_sz;
305 char *iv;
306
307 /* Get ciphering context from session ID */
308 DMSG("Session %p: reset initial vector", session);
309 sess = (struct aes_cipher *)session;
310
311 /* Safely get the invocation parameters */
312 if (param_types != exp_param_types)
313 return TEE_ERROR_BAD_PARAMETERS;
314
315 iv = params[0].memref.buffer;
316 iv_sz = params[0].memref.size;
317
318 /*
319 * Init cipher operation with the initialization vector.
320 */
321 TEE_CipherInit(sess->op_handle, iv, iv_sz);
322
323 return TEE_SUCCESS;
324 }
325
326 /*
327 * Process command TA_AES_CMD_CIPHER. API in aes_ta.h
328 */
cipher_buffer(void * session,uint32_t param_types,TEE_Param params[4])329 static TEE_Result cipher_buffer(void *session, uint32_t param_types,
330 TEE_Param params[4])
331 {
332 const uint32_t exp_param_types =
333 TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
334 TEE_PARAM_TYPE_MEMREF_OUTPUT,
335 TEE_PARAM_TYPE_NONE,
336 TEE_PARAM_TYPE_NONE);
337 struct aes_cipher *sess;
338
339 /* Get ciphering context from session ID */
340 DMSG("Session %p: cipher buffer", session);
341 sess = (struct aes_cipher *)session;
342
343 /* Safely get the invocation parameters */
344 if (param_types != exp_param_types)
345 return TEE_ERROR_BAD_PARAMETERS;
346
347 if (params[1].memref.size < params[0].memref.size) {
348 EMSG("Bad sizes: in %d, out %d", params[0].memref.size,
349 params[1].memref.size);
350 return TEE_ERROR_BAD_PARAMETERS;
351 }
352
353 if (sess->op_handle == TEE_HANDLE_NULL)
354 return TEE_ERROR_BAD_STATE;
355
356 /*
357 * Process ciphering operation on provided buffers
358 */
359 return TEE_CipherUpdate(sess->op_handle,
360 params[0].memref.buffer, params[0].memref.size,
361 params[1].memref.buffer, ¶ms[1].memref.size);
362 }
363
TA_CreateEntryPoint(void)364 TEE_Result TA_CreateEntryPoint(void)
365 {
366 /* Nothing to do */
367 return TEE_SUCCESS;
368 }
369
TA_DestroyEntryPoint(void)370 void TA_DestroyEntryPoint(void)
371 {
372 /* Nothing to do */
373 }
374
TA_OpenSessionEntryPoint(uint32_t __unused param_types,TEE_Param __unused params[4],void __unused ** session)375 TEE_Result TA_OpenSessionEntryPoint(uint32_t __unused param_types,
376 TEE_Param __unused params[4],
377 void __unused **session)
378 {
379 struct aes_cipher *sess;
380
381 /*
382 * Allocate and init ciphering materials for the session.
383 * The address of the structure is used as session ID for
384 * the client.
385 */
386 sess = TEE_Malloc(sizeof(*sess), 0);
387 if (!sess)
388 return TEE_ERROR_OUT_OF_MEMORY;
389
390 sess->key_handle = TEE_HANDLE_NULL;
391 sess->op_handle = TEE_HANDLE_NULL;
392
393 *session = (void *)sess;
394 DMSG("Session %p: newly allocated", *session);
395
396 return TEE_SUCCESS;
397 }
398
TA_CloseSessionEntryPoint(void * session)399 void TA_CloseSessionEntryPoint(void *session)
400 {
401 struct aes_cipher *sess;
402
403 /* Get ciphering context from session ID */
404 DMSG("Session %p: release session", session);
405 sess = (struct aes_cipher *)session;
406
407 /* Release the session resources */
408 if (sess->key_handle != TEE_HANDLE_NULL)
409 TEE_FreeTransientObject(sess->key_handle);
410 if (sess->op_handle != TEE_HANDLE_NULL)
411 TEE_FreeOperation(sess->op_handle);
412 TEE_Free(sess);
413 }
414
TA_InvokeCommandEntryPoint(void * session,uint32_t cmd,uint32_t param_types,TEE_Param params[4])415 TEE_Result TA_InvokeCommandEntryPoint(void *session,
416 uint32_t cmd,
417 uint32_t param_types,
418 TEE_Param params[4])
419 {
420 switch (cmd) {
421 case TA_AES_CMD_PREPARE:
422 return alloc_resources(session, param_types, params);
423 case TA_AES_CMD_SET_KEY:
424 return set_aes_key(session, param_types, params);
425 case TA_AES_CMD_SET_IV:
426 return reset_aes_iv(session, param_types, params);
427 case TA_AES_CMD_CIPHER:
428 return cipher_buffer(session, param_types, params);
429 default:
430 EMSG("Command ID 0x%x is not supported", cmd);
431 return TEE_ERROR_NOT_SUPPORTED;
432 }
433 }
434