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