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