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 #define TLOG_TAG "hwaes_srv"
18 
19 #include <assert.h>
20 #include <lib/hwaes_server/hwaes_server.h>
21 #include <lib/hwkey/hwkey.h>
22 #include <lib/tipc/tipc_srv.h>
23 #include <lk/err_ptr.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <trusty_log.h>
27 #include <uapi/err.h>
28 
29 #include <openssl/evp.h>
30 
31 #include <hwaes_consts.h>
32 
33 static EVP_CIPHER_CTX* cipher_ctx;
34 
crypt_init(void)35 static void crypt_init(void) {
36     assert(!cipher_ctx);
37 
38     cipher_ctx = EVP_CIPHER_CTX_new();
39     assert(cipher_ctx);
40 }
41 
crypt_shutdown(void)42 static void crypt_shutdown(void) {
43     EVP_CIPHER_CTX_free(cipher_ctx);
44     cipher_ctx = NULL;
45 }
46 
hwaes_check_arg_helper(size_t len,const uint8_t * data_ptr)47 static uint32_t hwaes_check_arg_helper(size_t len, const uint8_t* data_ptr) {
48     if (len == 0 || data_ptr == NULL) {
49         return HWAES_ERR_INVALID_ARGS;
50     }
51     return HWAES_NO_ERROR;
52 }
53 
hwaes_check_arg_in(const struct hwaes_arg_in * arg)54 static uint32_t hwaes_check_arg_in(const struct hwaes_arg_in* arg) {
55     return hwaes_check_arg_helper(arg->len, arg->data_ptr);
56 }
57 
hwaes_check_arg_out(const struct hwaes_arg_out * arg)58 static uint32_t hwaes_check_arg_out(const struct hwaes_arg_out* arg) {
59     return hwaes_check_arg_helper(arg->len, arg->data_ptr);
60 }
61 
hwaes_aes_op(const struct hwaes_aes_op_args * args)62 uint32_t hwaes_aes_op(const struct hwaes_aes_op_args* args) {
63     int evp_ret;
64     uint32_t rc;
65     const EVP_CIPHER* cipher;
66     int out_data_size;
67 
68     if (args->padding != HWAES_NO_PADDING) {
69         TLOGE("the padding type is not implemented yet\n");
70         return HWAES_ERR_NOT_IMPLEMENTED;
71     }
72 
73     rc = hwaes_check_arg_in(&args->key);
74     if (rc != HWAES_NO_ERROR) {
75         TLOGE("key argument is missing\n");
76         return rc;
77     }
78 
79     rc = hwaes_check_arg_in(&args->text_in);
80     if (rc != HWAES_NO_ERROR) {
81         TLOGE("text_in argument is missing\n");
82         return rc;
83     }
84 
85     rc = hwaes_check_arg_out(&args->text_out);
86     if (rc != HWAES_NO_ERROR) {
87         TLOGE("text_out argument is missing\n");
88         return rc;
89     }
90 
91     /*
92      * The current implementation does not support padding.
93      * So the size of input buffer is the same as output buffer.
94      */
95     if (args->text_in.len != args->text_out.len) {
96         TLOGE("text_in_len (%zd) is not equal to text_out_len (%zd)\n",
97               args->text_in.len, args->text_out.len);
98         return HWAES_ERR_INVALID_ARGS;
99     }
100 
101     uint8_t key_buffer[AES_KEY_MAX_SIZE] = {0};
102     struct hwaes_arg_in key = args->key;
103 
104     /* Fetch the real key contents if needed */
105     if (args->key_type == HWAES_OPAQUE_HANDLE) {
106         if (key.len > HWKEY_OPAQUE_HANDLE_MAX_SIZE) {
107             TLOGE("Wrong opaque handle length: %zu\n", key.len);
108             return HWAES_ERR_INVALID_ARGS;
109         }
110         if (key.data_ptr[key.len - 1] != 0) {
111             TLOGE("Opaque handle is not null-terminated\n");
112             return HWAES_ERR_INVALID_ARGS;
113         }
114         long ret = hwkey_open();
115         if (ret < 0) {
116             TLOGE("Failed to open connection to hwkey service\n");
117             return HWAES_ERR_GENERIC;
118         }
119         hwkey_session_t session = (hwkey_session_t)ret;
120         uint32_t key_len = sizeof(key_buffer);
121         ret = hwkey_get_keyslot_data(session, (const char*)key.data_ptr,
122                                      key_buffer, &key_len);
123         hwkey_close(session);
124         if (ret != NO_ERROR) {
125             TLOGE("Failed to retrieve opaque key: %ld\n", ret);
126             return HWAES_ERR_IO;
127         }
128 
129         key.data_ptr = key_buffer;
130         key.len = key_len;
131     }
132 
133     if (args->mode == HWAES_CBC_MODE) {
134         switch (key.len) {
135         case 16:
136             cipher = EVP_aes_128_cbc();
137             break;
138         case 32:
139             cipher = EVP_aes_256_cbc();
140             break;
141         default:
142             TLOGE("invalid key length: (%zd)\n", key.len);
143             return HWAES_ERR_INVALID_ARGS;
144         }
145 
146         if (hwaes_check_arg_in(&args->aad) == HWAES_NO_ERROR) {
147             TLOGE("AAD is not supported in CBC mode\n");
148             return HWAES_ERR_INVALID_ARGS;
149         }
150 
151         if (hwaes_check_arg_in(&args->tag_in) == HWAES_NO_ERROR ||
152             hwaes_check_arg_out(&args->tag_out) == HWAES_NO_ERROR) {
153             TLOGE("Authentication tag is not supported in CBC mode\n");
154             return HWAES_ERR_INVALID_ARGS;
155         }
156     } else if (args->mode == HWAES_GCM_MODE) {
157         switch (key.len) {
158         case 16:
159             cipher = EVP_aes_128_gcm();
160             break;
161         case 32:
162             cipher = EVP_aes_256_gcm();
163             break;
164         default:
165             TLOGE("invalid key length: (%zd)\n", key.len);
166             return HWAES_ERR_INVALID_ARGS;
167         }
168 
169         if (args->encrypt) {
170             if (hwaes_check_arg_in(&args->tag_in) == HWAES_NO_ERROR) {
171                 TLOGE("Input authentication tag set while encrypting in GCM mode\n");
172                 return HWAES_ERR_INVALID_ARGS;
173             }
174             if (hwaes_check_arg_out(&args->tag_out) != HWAES_NO_ERROR) {
175                 TLOGE("Missing output authentication tag in GCM mode\n");
176                 return HWAES_ERR_INVALID_ARGS;
177             }
178         } else {
179             if (hwaes_check_arg_in(&args->tag_in) != HWAES_NO_ERROR) {
180                 TLOGE("Missing input authentication tag in GCM mode\n");
181                 return HWAES_ERR_INVALID_ARGS;
182             }
183             if (hwaes_check_arg_out(&args->tag_out) == HWAES_NO_ERROR) {
184                 TLOGE("Output authentication tag set while decrypting in GCM mode\n");
185                 return HWAES_ERR_INVALID_ARGS;
186             }
187         }
188     } else {
189         TLOGE("AES mode %d is not implemented yet\n", args->mode);
190         return HWAES_ERR_NOT_IMPLEMENTED;
191     }
192 
193     assert(cipher_ctx);
194     EVP_CIPHER_CTX_reset(cipher_ctx);
195 
196     evp_ret = EVP_CipherInit_ex(cipher_ctx, cipher, NULL, NULL, NULL,
197                                 args->encrypt);
198     if (!evp_ret) {
199         TLOGE("EVP_CipherInit_ex failed\n");
200         return HWAES_ERR_GENERIC;
201     }
202 
203     if (args->text_in.len % EVP_CIPHER_CTX_block_size(cipher_ctx)) {
204         TLOGE("text_in_len (%zd) is not block aligned\n", args->text_in.len);
205         return HWAES_ERR_INVALID_ARGS;
206     }
207 
208     if (EVP_CIPHER_CTX_iv_length(cipher_ctx) != args->iv.len) {
209         TLOGE("invalid iv length: (%zd)\n", args->iv.len);
210         return HWAES_ERR_INVALID_ARGS;
211     }
212 
213     evp_ret = EVP_CipherInit_ex(cipher_ctx, cipher, NULL, key.data_ptr,
214                                 args->iv.data_ptr, args->encrypt);
215     if (!evp_ret) {
216         TLOGE("EVP_CipherInit_ex failed\n");
217         return HWAES_ERR_GENERIC;
218     }
219 
220     evp_ret = EVP_CIPHER_CTX_set_padding(cipher_ctx, 0);
221     if (!evp_ret) {
222         TLOGE("EVP_CIPHER_CTX_set_padding failed\n");
223         return HWAES_ERR_GENERIC;
224     }
225 
226     if (hwaes_check_arg_in(&args->aad) == HWAES_NO_ERROR) {
227         evp_ret = EVP_CipherUpdate(cipher_ctx, NULL, &out_data_size,
228                                    args->aad.data_ptr, args->aad.len);
229         if (evp_ret != 1) {
230             TLOGE("EVP CipherUpdate for AAD failed\n");
231             return HWAES_ERR_GENERIC;
232         }
233     }
234 
235     if (hwaes_check_arg_in(&args->tag_in) == HWAES_NO_ERROR) {
236         evp_ret = EVP_CIPHER_CTX_ctrl(cipher_ctx, EVP_CTRL_AEAD_SET_TAG,
237                                       args->tag_in.len,
238                                       (void*)args->tag_in.data_ptr);
239         if (evp_ret != 1) {
240             TLOGE("EVP set AEAD tag failed\n");
241             return HWAES_ERR_GENERIC;
242         }
243     }
244 
245     evp_ret = EVP_CipherUpdate(cipher_ctx, args->text_out.data_ptr,
246                                &out_data_size, args->text_in.data_ptr,
247                                args->text_in.len);
248     if (!evp_ret) {
249         TLOGE("EVP_CipherUpdate failed\n");
250         return HWAES_ERR_GENERIC;
251     }
252 
253     /*
254      * The assert fails if the memory corruption happens.
255      */
256     assert(out_data_size == (int)args->text_out.len);
257 
258     /*
259      * Currently we don't support padding.
260      */
261     evp_ret = EVP_CipherFinal_ex(cipher_ctx, NULL, &out_data_size);
262     if (!evp_ret) {
263         TLOGE("EVP_CipherFinal_ex failed\n");
264         return HWAES_ERR_GENERIC;
265     }
266 
267     if (hwaes_check_arg_out(&args->tag_out) == HWAES_NO_ERROR) {
268         evp_ret =
269                 EVP_CIPHER_CTX_ctrl(cipher_ctx, EVP_CTRL_AEAD_GET_TAG,
270                                     args->tag_out.len, args->tag_out.data_ptr);
271         if (evp_ret != 1) {
272             TLOGE("EVP get AEAD tag failed\n");
273             return HWAES_ERR_GENERIC;
274         }
275     }
276 
277     return HWAES_NO_ERROR;
278 }
279 
280 static const uuid_t apploader_uuid = APPLOADER_APP_UUID;
281 
282 static const uuid_t hwaes_unittest_uuid = HWAES_UNITTEST_APP_UUID;
283 
284 static const uuid_t hwaes_bench_uuid = HWAES_BENCH_APP_UUID;
285 
286 static const uuid_t internal_app_uuid = INTERNAL_APP_UUID;
287 
288 static const uuid_t* allowed_clients[] = {
289         &apploader_uuid,
290         &hwaes_bench_uuid,
291         &hwaes_unittest_uuid,
292         &internal_app_uuid,
293 };
294 
main(void)295 int main(void) {
296     int rc;
297     struct tipc_hset* hset;
298     TLOGE("hwaes server is using SW Crypto\n");
299 
300     hset = tipc_hset_create();
301     if (IS_ERR(hset)) {
302         TLOGE("failed (%d) to create handle set\n", PTR_ERR(hset));
303         return EXIT_FAILURE;
304     }
305 
306     rc = add_hwaes_service(hset, allowed_clients, countof(allowed_clients));
307     if (rc != NO_ERROR) {
308         TLOGE("failed (%d) to initialize hwaes service\n", rc);
309         return EXIT_FAILURE;
310     }
311 
312     crypt_init();
313     rc = tipc_run_event_loop(hset);
314 
315     TLOGE("hwaes server going down: (%d)\n", rc);
316     crypt_shutdown();
317     if (rc != NO_ERROR) {
318         return EXIT_FAILURE;
319     }
320     EXIT_SUCCESS;
321 }
322