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