1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2015, Linaro Limited
4 * All rights reserved.
5 */
6
7 #include <tee_internal_api_extensions.h>
8 #include <tee_internal_api.h>
9 #include <tee_ta_api.h>
10 #include <string.h>
11 #include <trace.h>
12
13 #include "ta_aes_perf.h"
14 #include "ta_aes_perf_priv.h"
15
16 #define CHECK(res, name, action) do { \
17 if ((res) != TEE_SUCCESS) { \
18 DMSG(name ": 0x%08x", (res)); \
19 action \
20 } \
21 } while(0)
22
23 #define TAG_LEN 128
24
25 static uint8_t iv[] = { 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
26 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF };
27 static int use_iv;
28
29 static TEE_OperationHandle crypto_op = NULL;
30 static uint32_t algo;
31
is_inbuf_a_secure_memref(TEE_Param * param)32 static bool is_inbuf_a_secure_memref(TEE_Param *param)
33 {
34 TEE_Result res = TEE_ERROR_GENERIC;
35
36 /*
37 * Check secure attribute for the referenced buffer
38 * Trust core on validity of the memref size: test only 1st byte
39 * instead of the overall buffer, and if it's not secure, assume
40 * the buffer is nonsecure.
41 */
42 res = TEE_CheckMemoryAccessRights(TEE_MEMORY_ACCESS_ANY_OWNER |
43 TEE_MEMORY_ACCESS_READ |
44 TEE_MEMORY_ACCESS_SECURE,
45 param->memref.buffer, 1);
46 return (res == TEE_SUCCESS);
47 }
48
is_outbuf_a_secure_memref(TEE_Param * param)49 static bool is_outbuf_a_secure_memref(TEE_Param *param)
50 {
51 TEE_Result res = TEE_ERROR_GENERIC;
52
53 /*
54 * Check secure attribute for the referenced buffer
55 * Trust core on validity of the memref size: test only 1st byte
56 * instead of the overall buffer, and if it's not secure, assume
57 * the buffer is nonsecure.
58 */
59 res = TEE_CheckMemoryAccessRights(TEE_MEMORY_ACCESS_ANY_OWNER |
60 TEE_MEMORY_ACCESS_WRITE |
61 TEE_MEMORY_ACCESS_SECURE,
62 param->memref.buffer, 1);
63 return (res == TEE_SUCCESS);
64 }
65
66 #if defined(CFG_CACHE_API)
flush_memref_buffer(TEE_Param * param)67 static TEE_Result flush_memref_buffer(TEE_Param *param)
68 {
69 TEE_Result res = TEE_ERROR_GENERIC;
70
71 res = TEE_CacheFlush(param->memref.buffer,
72 param->memref.size);
73 CHECK(res, "TEE_CacheFlush(in)", return res;);
74 return res;
75 }
76 #else
flush_memref_buffer(TEE_Param * param __unused)77 static __maybe_unused TEE_Result flush_memref_buffer(TEE_Param *param __unused)
78 {
79 return TEE_SUCCESS;
80 }
81 #endif /* CFG_CACHE_API */
82
cmd_process(uint32_t param_types,TEE_Param params[TEE_NUM_PARAMS],bool use_sdp)83 TEE_Result cmd_process(uint32_t param_types,
84 TEE_Param params[TEE_NUM_PARAMS],
85 bool use_sdp)
86 {
87 TEE_Result res = TEE_ERROR_GENERIC;
88 int n = 0;
89 int unit = 0;
90 void *in = NULL;
91 void *out = NULL;
92 uint32_t insz = 0;
93 uint32_t outsz = 0;
94 uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT,
95 TEE_PARAM_TYPE_MEMREF_INOUT,
96 TEE_PARAM_TYPE_VALUE_INPUT,
97 TEE_PARAM_TYPE_NONE);
98 bool secure_in = false;
99 bool secure_out = false;
100 TEE_Result (*do_update)(TEE_OperationHandle, const void *, uint32_t,
101 void *, uint32_t *) = NULL;
102
103 if (param_types != exp_param_types)
104 return TEE_ERROR_BAD_PARAMETERS;
105
106 if (use_sdp) {
107 /*
108 * Whatever is expected as memory reference, it is mandatory
109 * for SDP aware trusted applications of safely indentify all
110 * memory reference parameters. Hence these tests must be part
111 * of the performance test setup.
112 */
113 secure_in = is_inbuf_a_secure_memref(¶ms[0]);
114 secure_out = is_outbuf_a_secure_memref(¶ms[1]);
115
116 /*
117 * We could invalidate only the caches. We prefer to flush
118 * them in case 2 sub-buffers are accessed by TAs from a single
119 * allocated SDP memory buffer, and those are not cache-aligned.
120 * Invalidating might cause data loss in cache lines. Hence
121 * rather flush them all before accessing (in read or write).
122 */
123 if (secure_in) {
124 res = flush_memref_buffer(¶ms[0]);
125 CHECK(res, "pre-flush in memref param", return res;);
126 }
127 if (secure_out) {
128 res = flush_memref_buffer(¶ms[1]);
129 CHECK(res, "pre-flush out memref param", return res;);
130 }
131 }
132
133 in = params[0].memref.buffer;
134 insz = params[0].memref.size;
135 out = params[1].memref.buffer;
136 outsz = params[1].memref.size;
137 n = params[2].value.a;
138 unit = params[2].value.b;
139 if (!unit)
140 unit = insz;
141
142 if (algo == TEE_ALG_AES_GCM)
143 do_update = TEE_AEUpdate;
144 else
145 do_update = TEE_CipherUpdate;
146
147 while (n--) {
148 uint32_t i = 0;
149 for (i = 0; i < insz / unit; i++) {
150 res = do_update(crypto_op, in, unit, out, &outsz);
151 CHECK(res, "TEE_CipherUpdate/TEE_AEUpdate", return res;);
152 in = (void *)((uintptr_t)in + unit);
153 out = (void *)((uintptr_t)out + unit);
154 }
155 if (insz % unit) {
156 res = do_update(crypto_op, in, insz % unit, out, &outsz);
157 CHECK(res, "TEE_CipherUpdate/TEE_AEUpdate", return res;);
158 }
159 }
160
161 if (secure_out) {
162 /* intentionally flush output data from cache for SDP buffers */
163 res = flush_memref_buffer(¶ms[1]);
164 CHECK(res, "post-flush out memref param", return res;);
165 }
166
167 return TEE_SUCCESS;
168 }
169
cmd_prepare_key(uint32_t param_types,TEE_Param params[4])170 TEE_Result cmd_prepare_key(uint32_t param_types, TEE_Param params[4])
171 {
172 TEE_Result res = TEE_ERROR_GENERIC;
173 TEE_ObjectHandle hkey = TEE_HANDLE_NULL;
174 TEE_ObjectHandle hkey2 = TEE_HANDLE_NULL;
175 TEE_Attribute attr = { };
176 uint32_t mode = 0;
177 uint32_t op_keysize = 0;
178 uint32_t keysize = 0;
179 const uint8_t *ivp = NULL;
180 size_t ivlen = 0;
181 static uint8_t aes_key[] = { 0x00, 0x01, 0x02, 0x03,
182 0x04, 0x05, 0x06, 0x07,
183 0x08, 0x09, 0x0A, 0x0B,
184 0x0C, 0x0D, 0x0E, 0x0F,
185 0x10, 0x11, 0x12, 0x13,
186 0x14, 0x15, 0x16, 0x17,
187 0x18, 0x19, 0x1A, 0x1B,
188 0x1C, 0x1D, 0x1E, 0x1F };
189 static uint8_t aes_key2[] = { 0x20, 0x21, 0x22, 0x23,
190 0x24, 0x25, 0x26, 0x27,
191 0x28, 0x29, 0x2A, 0x2B,
192 0x2C, 0x2D, 0x2E, 0x2F,
193 0x30, 0x31, 0x32, 0x33,
194 0x34, 0x35, 0x36, 0x37,
195 0x38, 0x39, 0x3A, 0x3B,
196 0x3C, 0x3D, 0x3E, 0x3F };
197 uint32_t exp_param_types = TEE_PARAM_TYPES(TEE_PARAM_TYPE_VALUE_INPUT,
198 TEE_PARAM_TYPE_VALUE_INPUT,
199 TEE_PARAM_TYPE_NONE,
200 TEE_PARAM_TYPE_NONE);
201
202 if (param_types != exp_param_types)
203 return TEE_ERROR_BAD_PARAMETERS;
204
205 mode = params[0].value.a ? TEE_MODE_DECRYPT : TEE_MODE_ENCRYPT;
206 keysize = params[0].value.b;
207 op_keysize = keysize;
208
209 switch (params[1].value.a) {
210 case TA_AES_ECB:
211 algo = TEE_ALG_AES_ECB_NOPAD;
212 use_iv = 0;
213 break;
214 case TA_AES_CBC:
215 algo = TEE_ALG_AES_CBC_NOPAD;
216 use_iv = 1;
217 break;
218 case TA_AES_CTR:
219 algo = TEE_ALG_AES_CTR;
220 use_iv = 1;
221 break;
222 case TA_AES_XTS:
223 algo = TEE_ALG_AES_XTS;
224 use_iv = 1;
225 op_keysize *= 2;
226 break;
227 case TA_AES_GCM:
228 algo = TEE_ALG_AES_GCM;
229 use_iv = 1;
230 break;
231 default:
232 return TEE_ERROR_BAD_PARAMETERS;
233 }
234
235 cmd_clean_res();
236
237 res = TEE_AllocateOperation(&crypto_op, algo, mode, op_keysize);
238 CHECK(res, "TEE_AllocateOperation", return res;);
239
240 res = TEE_AllocateTransientObject(TEE_TYPE_AES, keysize, &hkey);
241 CHECK(res, "TEE_AllocateTransientObject", return res;);
242
243 attr.attributeID = TEE_ATTR_SECRET_VALUE;
244 attr.content.ref.buffer = aes_key;
245 attr.content.ref.length = keysize / 8;
246
247 res = TEE_PopulateTransientObject(hkey, &attr, 1);
248 CHECK(res, "TEE_PopulateTransientObject", return res;);
249
250 if (algo == TEE_ALG_AES_XTS) {
251 res = TEE_AllocateTransientObject(TEE_TYPE_AES, keysize,
252 &hkey2);
253 CHECK(res, "TEE_AllocateTransientObject", return res;);
254
255 attr.content.ref.buffer = aes_key2;
256
257 res = TEE_PopulateTransientObject(hkey2, &attr, 1);
258 CHECK(res, "TEE_PopulateTransientObject", return res;);
259
260 res = TEE_SetOperationKey2(crypto_op, hkey, hkey2);
261 CHECK(res, "TEE_SetOperationKey2", return res;);
262
263 TEE_FreeTransientObject(hkey2);
264 } else {
265 res = TEE_SetOperationKey(crypto_op, hkey);
266 CHECK(res, "TEE_SetOperationKey", return res;);
267 }
268
269 TEE_FreeTransientObject(hkey);
270
271 if (use_iv) {
272 ivp = iv;
273 ivlen = sizeof(iv);
274 } else {
275 ivp = NULL;
276 ivlen = 0;
277 }
278
279 if (algo == TEE_ALG_AES_GCM) {
280 return TEE_AEInit(crypto_op, ivp, ivlen, TAG_LEN, 0, 0);
281 } else {
282 TEE_CipherInit(crypto_op, ivp, ivlen);
283 return TEE_SUCCESS;
284 }
285 }
286
cmd_clean_res(void)287 void cmd_clean_res(void)
288 {
289 if (crypto_op)
290 TEE_FreeOperation(crypto_op);
291 }
292