1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <assert.h>
18 #include <lib/tipc/tipc.h>
19 #include <lk/macros.h>
20 #include <stdbool.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/mman.h>
25 #include <trusty_ipc.h>
26 #include <trusty_log.h>
27 #include <uapi/err.h>
28
29 #include <interface/hwaes/hwaes.h>
30 #include <lib/hwaes/hwaes.h>
31
32 #include <inttypes.h>
33
34 #define TLOG_TAG "libhwaes"
35
36 /**
37 * struct hwaes_iov - an wrapper of an array of iovec.
38 * @iov: array of iovec.
39 * @num_iov: number of iovec.
40 * @total_len: total length of the tipc message.
41 */
42 struct hwaes_iov {
43 struct iovec iov[TIPC_MAX_MSG_PARTS];
44 size_t num_iov;
45 size_t total_len;
46 };
47
48 /**
49 * struct hwaes_shm - an wrapper of an array of shared memory handles.
50 * @handles: array of shared memory handles.
51 * @num_handles: number of shared memory handles.
52 */
53 struct hwaes_shm {
54 handle_t handles[HWAES_MAX_NUM_HANDLES];
55 size_t num_handles;
56 };
57
58 /**
59 * hwaes_err_to_tipc_err() - translates hwaes err value to tipc/lk err
60 * value
61 * @hwaes_err: hwaes err value
62 *
63 * Returns: enum hwaes_err value
64 */
hwaes_err_to_tipc_err(enum hwaes_err hwaes_err)65 static int hwaes_err_to_tipc_err(enum hwaes_err hwaes_err) {
66 switch (hwaes_err) {
67 case HWAES_NO_ERROR:
68 return NO_ERROR;
69 case HWAES_ERR_INVALID_ARGS:
70 return ERR_INVALID_ARGS;
71 case HWAES_ERR_IO:
72 return ERR_IO;
73 case HWAES_ERR_BAD_HANDLE:
74 return ERR_BAD_HANDLE;
75 case HWAES_ERR_NOT_IMPLEMENTED:
76 return ERR_NOT_IMPLEMENTED;
77 default:
78 return ERR_GENERIC;
79 }
80 }
81
82 /**
83 * hwaes_set_shm_arg_helper() - helper to set shared memory for argument.
84 * @data_ptr: pointer to the argument data.
85 * @len: length of the argument data.
86 * @shm_hd_ptr: pointer to the shared memory descriptor handler.
87 * @write: the write flag of the shared memory.
88 * @data_desc_ptr: pointer to data descriptor.
89 * @shm_descs: array of shared memory descriptors.
90 * @shm_wrapper_ptr: pointer to the wrapper of shared memmory array.
91 *
92 */
hwaes_set_shm_arg_helper(const uint8_t * data_ptr,size_t len,struct hwcrypt_shm_hd * shm_hd_ptr,bool write,struct hwaes_data_desc * data_desc_ptr,struct hwaes_shm_desc * shm_descs,struct hwaes_shm * shm_wrapper_ptr)93 static void hwaes_set_shm_arg_helper(const uint8_t* data_ptr,
94 size_t len,
95 struct hwcrypt_shm_hd* shm_hd_ptr,
96 bool write,
97 struct hwaes_data_desc* data_desc_ptr,
98 struct hwaes_shm_desc* shm_descs,
99 struct hwaes_shm* shm_wrapper_ptr) {
100 size_t shm_num = shm_wrapper_ptr->num_handles;
101 size_t i;
102
103 if (shm_hd_ptr) {
104 for (i = 0; i < shm_num; i++) {
105 if (shm_wrapper_ptr->handles[i] == shm_hd_ptr->handle) {
106 break;
107 }
108 }
109
110 if (i == shm_num) {
111 shm_descs[i].size = shm_hd_ptr->size;
112 shm_wrapper_ptr->handles[i] = shm_hd_ptr->handle;
113 shm_wrapper_ptr->num_handles = shm_num + 1;
114 }
115
116 if (write) {
117 shm_descs[i].write = 1U;
118 }
119
120 const uint8_t* shm_base = shm_hd_ptr->base;
121 data_desc_ptr->offset = data_ptr - shm_base;
122 data_desc_ptr->len = len;
123 data_desc_ptr->shm_idx = i;
124 } else {
125 data_desc_ptr->shm_idx = HWAES_INVALID_INDEX;
126 }
127 }
128
129 /**
130 * hwaes_set_shm_arg_out() - set shared memory for output argument.
131 * @arg_ptr: pointer to the output arg.
132 * @data_desc_ptr: pointer to data descriptor.
133 * @shm_descs: array of shared memory descriptors.
134 * @shm_wrapper_ptr: pointer to the wrapper of shared memmory array.
135 *
136 */
hwaes_set_shm_arg_out(const struct hwcrypt_arg_out * arg_ptr,struct hwaes_data_desc * data_desc_ptr,struct hwaes_shm_desc * shm_descs,struct hwaes_shm * shm_wrapper_ptr)137 static void hwaes_set_shm_arg_out(const struct hwcrypt_arg_out* arg_ptr,
138 struct hwaes_data_desc* data_desc_ptr,
139 struct hwaes_shm_desc* shm_descs,
140 struct hwaes_shm* shm_wrapper_ptr) {
141 hwaes_set_shm_arg_helper(arg_ptr->data_ptr, arg_ptr->len,
142 arg_ptr->shm_hd_ptr, true, data_desc_ptr,
143 shm_descs, shm_wrapper_ptr);
144 }
145
146 /**
147 * hwaes_set_shm_arg_in() - set shared memory for input argument.
148 * @arg_ptr: pointer to the input arg.
149 * @data_desc_ptr: pointer to data descriptor.
150 * @shm_descs: array of shared memory descriptors.
151 * @shm_wrapper_ptr: pointer to the wrapper of shared memory array.
152 *
153 */
hwaes_set_shm_arg_in(const struct hwcrypt_arg_in * arg_ptr,struct hwaes_data_desc * data_desc_ptr,struct hwaes_shm_desc * shm_descs,struct hwaes_shm * shm_wrapper_ptr)154 static void hwaes_set_shm_arg_in(const struct hwcrypt_arg_in* arg_ptr,
155 struct hwaes_data_desc* data_desc_ptr,
156 struct hwaes_shm_desc* shm_descs,
157 struct hwaes_shm* shm_wrapper_ptr) {
158 hwaes_set_shm_arg_helper(arg_ptr->data_ptr, arg_ptr->len,
159 arg_ptr->shm_hd_ptr, false, data_desc_ptr,
160 shm_descs, shm_wrapper_ptr);
161 }
162
163 /**
164 * hwaes_set_iov_helper() - helper to set iov for argument
165 * @data_ptr: pointer to the argument data.
166 * @len: length of the argument data.
167 * @iov_wrapper_ptr: pointer to a wrapper for an iovec array.
168 *
169 */
hwaes_set_iov_helper(const void * data_ptr,size_t len,struct hwaes_iov * iov_wrapper_ptr)170 static void hwaes_set_iov_helper(const void* data_ptr,
171 size_t len,
172 struct hwaes_iov* iov_wrapper_ptr) {
173 size_t iov_num = iov_wrapper_ptr->num_iov;
174
175 assert(iov_num < TIPC_MAX_MSG_PARTS);
176
177 /* iovec's iov_base is not const, so a cast is required*/
178 iov_wrapper_ptr->iov[iov_num].iov_base = (void*)data_ptr;
179 iov_wrapper_ptr->iov[iov_num].iov_len = len;
180 iov_wrapper_ptr->total_len += len;
181 iov_num++;
182 iov_wrapper_ptr->num_iov = iov_num;
183 }
184
185 /**
186 * hwaes_pad_iov_helper() - helper to set iov for argument and add pad
187 * before the buffer to satisfy the alignment requirements
188 * @pad_ptr: pointer to the pad buffer.
189 * @alignment: alignment required for the next field
190 * @iov_wrapper_ptr: pointer to a wrapper for an iovec array.
191 *
192 * This may add an iov entry to insert padding bytes from `pad_ptr` to ensure
193 * the next bytes written will be aligned to the specified offset from the start
194 * of the data stream. If the receiving server reads the message into a
195 * suitably aligned buffer, the alignment of the next bytes can be controlled to
196 * meet DMA hardware or cache-line alignment requirements.
197 */
hwaes_pad_iov_helper(const void * pad_ptr,size_t alignment,struct hwaes_iov * iov_wrapper_ptr)198 static void hwaes_pad_iov_helper(const void* pad_ptr,
199 size_t alignment,
200 struct hwaes_iov* iov_wrapper_ptr) {
201 size_t pad_size = ROUND_UP(iov_wrapper_ptr->total_len, alignment) -
202 iov_wrapper_ptr->total_len;
203 if (pad_size > 0) {
204 hwaes_set_iov_helper(pad_ptr, pad_size, iov_wrapper_ptr);
205 }
206 }
207
208 /**
209 * hwaes_set_iov_arg_helper() - helper to set iov for argument
210 * @data_ptr: pointer to the argument data.
211 * @len: length of the argument data.
212 * @data_desc_ptr: pointer to data descriptor.
213 * @iov_wrapper_ptr: pointer to a wrapper for an iovec array.
214 *
215 */
hwaes_set_iov_arg_helper(const void * data_ptr,size_t len,struct hwaes_data_desc * data_desc_ptr,struct hwaes_iov * iov_wrapper_ptr)216 static void hwaes_set_iov_arg_helper(const void* data_ptr,
217 size_t len,
218 struct hwaes_data_desc* data_desc_ptr,
219 struct hwaes_iov* iov_wrapper_ptr) {
220 data_desc_ptr->offset = iov_wrapper_ptr->total_len;
221 data_desc_ptr->len = len;
222 hwaes_set_iov_helper(data_ptr, len, iov_wrapper_ptr);
223 }
224
225 /**
226 * hwaes_set_iov_arg_in() - set iovec for input argument.
227 * @arg_ptr: pointer to the input arg.
228 * @data_desc_ptr: pointer to data descriptor.
229 * @iov_wrapper_ptr: pointer to a wrapper for an iovec array.
230 *
231 */
hwaes_set_iov_arg_in(const struct hwcrypt_arg_in * arg_ptr,struct hwaes_data_desc * data_desc_ptr,struct hwaes_iov * iov_wrapper_ptr)232 static void hwaes_set_iov_arg_in(const struct hwcrypt_arg_in* arg_ptr,
233 struct hwaes_data_desc* data_desc_ptr,
234 struct hwaes_iov* iov_wrapper_ptr) {
235 if (data_desc_ptr->shm_idx == HWAES_INVALID_INDEX && arg_ptr->len != 0) {
236 hwaes_set_iov_arg_helper(arg_ptr->data_ptr, arg_ptr->len, data_desc_ptr,
237 iov_wrapper_ptr);
238 }
239 }
240
241 /**
242 * hwaes_set_iov_arg_out() - set iovec for output argument.
243 * @arg_ptr: pointer to the output arg.
244 * @data_desc_ptr: pointer to data descriptor.
245 * @iov_wrapper_ptr: pointer to a wrapper for an iovec array.
246 *
247 */
hwaes_set_iov_arg_out(const struct hwcrypt_arg_out * arg_ptr,struct hwaes_data_desc * data_desc_ptr,struct hwaes_iov * iov_wrapper_ptr)248 static void hwaes_set_iov_arg_out(const struct hwcrypt_arg_out* arg_ptr,
249 struct hwaes_data_desc* data_desc_ptr,
250 struct hwaes_iov* iov_wrapper_ptr) {
251 if (data_desc_ptr->shm_idx == HWAES_INVALID_INDEX && arg_ptr->len != 0) {
252 hwaes_set_iov_arg_helper(arg_ptr->data_ptr, arg_ptr->len, data_desc_ptr,
253 iov_wrapper_ptr);
254 }
255 }
256
257 /**
258 * hwaes_send_req() - sends request to hwaes server
259 * @session: the hwaes session handle.
260 * @req_iov_ptr: pointer to the request iovec wrapper.
261 * @shm_ptr: pointer to an wrapper of an shared memory handles array.
262 *
263 * Returns: NO_ERROR on success, negative error code on failure
264 */
hwaes_send_req(hwaes_session_t session,struct hwaes_iov * req_iov_ptr,struct hwaes_shm * shm_ptr)265 static int hwaes_send_req(hwaes_session_t session,
266 struct hwaes_iov* req_iov_ptr,
267 struct hwaes_shm* shm_ptr) {
268 int rc;
269
270 struct ipc_msg ipc_msg = {
271 .iov = req_iov_ptr->iov,
272 .num_iov = req_iov_ptr->num_iov,
273 .handles = shm_ptr->handles,
274 .num_handles = shm_ptr->num_handles,
275 };
276
277 rc = send_msg(session, &ipc_msg);
278 if (rc < 0 || (size_t)rc != req_iov_ptr->total_len) {
279 if (rc >= 0) {
280 rc = ERR_BAD_LEN;
281 }
282 TLOGE("failed to send_msg (%d)\n", rc);
283 return rc;
284 }
285 return NO_ERROR;
286 }
287
288 /**
289 * hwaes_recv_resp() - receives response hwaes server
290 * @session: the hwaes session handle.
291 * @resp_iov_ptr: pointer to the response iovec wrapper.
292 * @resp_msg_size: pointer to the response message size.
293 *
294 * Returns: NO_ERROR on success, negative error code on failure
295 */
hwaes_recv_resp(hwaes_session_t session,struct hwaes_iov * resp_iov_ptr,size_t * resp_msg_size)296 static int hwaes_recv_resp(hwaes_session_t session,
297 struct hwaes_iov* resp_iov_ptr,
298 size_t* resp_msg_size) {
299 int rc;
300 uevent_t uevt;
301
302 rc = wait(session, &uevt, INFINITE_TIME);
303 if (rc != NO_ERROR) {
304 TLOGE("failed to wait (%d)\n", rc);
305 return rc;
306 }
307
308 ipc_msg_info_t msg_inf;
309
310 rc = get_msg(session, &msg_inf);
311 if (rc != NO_ERROR) {
312 TLOGE("failed to get_msg (%d)\n", rc);
313 return rc;
314 }
315
316 if (msg_inf.len < sizeof(struct hwaes_resp)) {
317 TLOGE("msg size (%zu) is less than size of resp header (%zu)\n",
318 msg_inf.len, sizeof(struct hwaes_resp));
319 rc = ERR_BAD_LEN;
320 goto out;
321 }
322
323 struct ipc_msg ipc_msg = {
324 .iov = resp_iov_ptr->iov,
325 .num_iov = resp_iov_ptr->num_iov,
326 .handles = NULL,
327 .num_handles = 0,
328 };
329 rc = read_msg(session, msg_inf.id, 0, &ipc_msg);
330
331 if (rc != (int)msg_inf.len) {
332 TLOGE("failed (%d) to read_msg()\n", rc);
333 if (rc >= 0) {
334 rc = ERR_BAD_LEN;
335 }
336 goto out;
337 }
338
339 *resp_msg_size = rc;
340 rc = NO_ERROR;
341 out:
342 put_msg(session, msg_inf.id);
343 return rc;
344 }
345
346 /**
347 * hwaes_crypt() - Perform AES operation. It is a helper function
348 * @session: session handle retrieved from hwaes_open.
349 * @args: arguments for the AES operation.
350 * @encrypt: flag to indicate encrypt (true) or decrypt (false).
351 *
352 * Return: NO_ERROR on success, error code less than 0 on error.
353 *
354 */
hwaes_crypt(hwaes_session_t session,const struct hwcrypt_args * args,bool encrypt)355 static int hwaes_crypt(hwaes_session_t session,
356 const struct hwcrypt_args* args,
357 bool encrypt) {
358 int rc;
359
360 if (session == INVALID_IPC_HANDLE) {
361 TLOGE("invalid session handle\n");
362 return ERR_BAD_HANDLE;
363 }
364
365 struct hwaes_req req = {
366 .cmd = HWAES_AES,
367 };
368 struct hwaes_resp resp = {0};
369
370 struct hwaes_aes_req cmd_header = {
371 .key_type = args->key_type,
372 .padding = args->padding,
373 .mode = args->mode,
374 .encrypt = encrypt ? 1 : 0,
375 };
376
377 struct hwaes_iov req_iov = {0};
378 struct hwaes_iov resp_iov = {0};
379 struct hwaes_shm shm = {0};
380 struct hwaes_shm_desc shm_descs[HWAES_MAX_NUM_HANDLES] = {0};
381
382 hwaes_set_shm_arg_in(&args->key, &cmd_header.key, shm_descs, &shm);
383 hwaes_set_shm_arg_in(&args->iv, &cmd_header.iv, shm_descs, &shm);
384 hwaes_set_shm_arg_in(&args->aad, &cmd_header.aad, shm_descs, &shm);
385 hwaes_set_shm_arg_in(&args->text_in, &cmd_header.text_in, shm_descs, &shm);
386 hwaes_set_shm_arg_in(&args->tag_in, &cmd_header.tag_in, shm_descs, &shm);
387
388 hwaes_set_shm_arg_out(&args->text_out, &cmd_header.text_out, shm_descs,
389 &shm);
390 hwaes_set_shm_arg_out(&args->tag_out, &cmd_header.tag_out, shm_descs, &shm);
391
392 cmd_header.num_handles = shm.num_handles;
393
394 hwaes_set_iov_helper(&req, sizeof(req), &req_iov);
395 hwaes_set_iov_helper(&cmd_header, sizeof(cmd_header), &req_iov);
396 hwaes_set_iov_helper(shm_descs,
397 shm.num_handles * sizeof(struct hwaes_shm_desc),
398 &req_iov);
399
400 hwaes_set_iov_arg_in(&args->key, &cmd_header.key, &req_iov);
401 hwaes_set_iov_arg_in(&args->iv, &cmd_header.iv, &req_iov);
402
403 uint8_t padd_buf[MAX(HWAES_TEXT_IN_BUF_ALIGNMENT,
404 HWAES_TEXT_OUT_BUF_ALIGNMENT)] = {0};
405 if (cmd_header.aad.shm_idx == HWAES_INVALID_INDEX && args->aad.len != 0) {
406 hwaes_pad_iov_helper(padd_buf, HWAES_TEXT_IN_BUF_ALIGNMENT, &req_iov);
407 }
408 hwaes_set_iov_arg_in(&args->aad, &cmd_header.aad, &req_iov);
409
410 if (cmd_header.text_in.shm_idx == HWAES_INVALID_INDEX &&
411 args->text_in.len != 0) {
412 hwaes_pad_iov_helper(padd_buf, HWAES_TEXT_IN_BUF_ALIGNMENT, &req_iov);
413 }
414 hwaes_set_iov_arg_in(&args->text_in, &cmd_header.text_in, &req_iov);
415 hwaes_set_iov_arg_in(&args->tag_in, &cmd_header.tag_in, &req_iov);
416
417 hwaes_set_iov_helper(&resp, sizeof(resp), &resp_iov);
418
419 if (cmd_header.text_out.shm_idx == HWAES_INVALID_INDEX &&
420 args->text_out.len != 0) {
421 hwaes_pad_iov_helper(padd_buf, HWAES_TEXT_OUT_BUF_ALIGNMENT, &resp_iov);
422 }
423 hwaes_set_iov_arg_out(&args->text_out, &cmd_header.text_out, &resp_iov);
424 hwaes_set_iov_arg_out(&args->tag_out, &cmd_header.tag_out, &resp_iov);
425
426 rc = hwaes_send_req(session, &req_iov, &shm);
427 if (rc != NO_ERROR) {
428 TLOGE("failed to hwaes_send_req (%d)\n", rc);
429 return rc;
430 }
431
432 size_t resp_msg_size;
433 rc = hwaes_recv_resp(session, &resp_iov, &resp_msg_size);
434 if (rc != NO_ERROR) {
435 TLOGE("failed to hwaes_recv_resp (%d)\n", rc);
436 return rc;
437 }
438
439 if (resp.cmd != (req.cmd | HWAES_RESP_BIT)) {
440 TLOGE("invalid response cmd (0x%x) for request cmd (0x%x)\n", resp.cmd,
441 req.cmd);
442 return ERR_NOT_VALID;
443 }
444
445 if (resp.result == HWAES_NO_ERROR && resp_msg_size != resp_iov.total_len) {
446 TLOGE("wrong response message length (%zu)\n", resp_msg_size);
447 return ERR_BAD_LEN;
448 }
449
450 return hwaes_err_to_tipc_err(resp.result);
451 }
452
hwaes_open(hwaes_session_t * session)453 int hwaes_open(hwaes_session_t* session) {
454 int rc = tipc_connect(session, HWAES_PORT);
455 if (rc < 0) {
456 TLOGE("Failed to connect to %s\n", HWAES_PORT);
457 }
458 return rc;
459 }
460
hwaes_encrypt(hwaes_session_t session,const struct hwcrypt_args * args)461 int hwaes_encrypt(hwaes_session_t session, const struct hwcrypt_args* args) {
462 return hwaes_crypt(session, args, true);
463 }
464
hwaes_decrypt(hwaes_session_t session,const struct hwcrypt_args * args)465 int hwaes_decrypt(hwaes_session_t session, const struct hwcrypt_args* args) {
466 return hwaes_crypt(session, args, false);
467 }
468
hwaes_close(hwaes_session_t session)469 void hwaes_close(hwaes_session_t session) {
470 close(session);
471 }
472