Add data structures
[platform/core/security/libwebappenc.git] / srcs / key_handler.c
1 /*
2  *  Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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  * @file        key_handler.c
18  * @author      Dongsun Lee (ds73.lee@samsung.com)
19  * @version     1.0
20  * @brief       Key manupulatation.
21  */
22 #include "key_handler.h"
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <dirent.h>
28 #include <unistd.h>
29
30 #include <tzplatform_config.h>
31
32 #include "wae_log.h"
33 #include "crypto_service.h"
34 #include "key_manager.h"
35 #include "decrypt_migrated_wgt.h"
36
37 #define RANDOM_FILE                 "/dev/urandom"
38 #define APP_DEK_KEK_PRIKEY_PASSWORD "wae_appdek_kek_1q2w3e4r"
39 #define APP_DEK_FILE_PFX            "WAE_APP_DEK"
40
41 #define DEK_LEN        32
42 #define IV_LEN         16
43 #define MAX_PKGID_LEN  256
44 #define MAX_CACHE_SIZE 100
45
46 static unsigned char AES_CBC_IV[IV_LEN] = {
47         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
48         0x08, 0x39, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
49 };
50
51 static crypto_element_map_s *_map;
52
53 static void deinit_lib(void) __attribute__((destructor));
54 static void deinit_lib(void)
55 {
56         crypto_element_map_destroy(_map);
57 }
58
59 static const crypto_element_s *_get_app_ce_from_cache(const char *pkg_id)
60 {
61         return crypto_element_map_get(_map, pkg_id);
62 }
63
64 static int _add_app_ce_to_cache(const char *pkg_id, crypto_element_s *ce)
65 {
66         return crypto_element_map_add(&_map, pkg_id, ce);
67 }
68
69 void _remove_app_ce_from_cache(const char *pkg_id)
70 {
71         crypto_element_map_remove(&_map, pkg_id);
72 }
73
74 int _get_random(raw_buffer_s *rb)
75 {
76         if (!is_buffer_valid(rb))
77                 return WAE_ERROR_INVALID_PARAMETER;
78
79         FILE *f = fopen(RANDOM_FILE, "r");
80
81         if (f == NULL) {
82                 WAE_SLOGE("Failed to open random file source: %s", RANDOM_FILE);
83                 return WAE_ERROR_FILE;
84         }
85
86         size_t i = 0;
87         int ch = 0;
88         while (i < rb->size && (ch = fgetc(f) != EOF))
89                 rb->buf[i++] = (unsigned char)ch;
90
91         fclose(f);
92
93         return WAE_ERROR_NONE;
94 }
95
96 static const char *_get_dek_kek_pub_key_path()
97 {
98         return tzplatform_mkpath4(TZ_SYS_SHARE, "wae", "app_dek", "WAE_APPDEK_KEK_PublicKey.pem");
99 }
100
101 static const char *_get_dek_kek_pri_key_path()
102 {
103         return tzplatform_mkpath4(TZ_SYS_SHARE, "wae", "app_dek", "WAE_APPDEK_KEK_PrivateKey.pem");
104 }
105
106 static const char *_get_dek_store_path()
107 {
108         return tzplatform_mkpath3(TZ_SYS_SHARE, "wae", "app_dek");
109 }
110
111 static int _write_to_file(const char *path, const raw_buffer_s *data)
112 {
113         if (path == NULL || data == NULL || data->buf == NULL || data->size == 0)
114                 return WAE_ERROR_INVALID_PARAMETER;
115
116         FILE *f = fopen(path, "w");
117
118         if (f == NULL) {
119                 WAE_SLOGE("WAE: Fail to open a file. file=%s", path);
120                 return WAE_ERROR_FILE;
121         }
122
123         int write_len = fwrite(data->buf, 1, data->size, f);
124
125         fclose(f);
126
127         if (write_len != (int)data->size) {
128                 WAE_SLOGE("WAE: Fail to write a file. file=%s", path);
129                 return WAE_ERROR_FILE;
130         }
131
132         return WAE_ERROR_NONE;
133 }
134
135 static int _read_from_file(const char *path, raw_buffer_s **pdata)
136 {
137         int ret = WAE_ERROR_NONE;
138         raw_buffer_s *data = NULL;
139         int ch = 0;
140         int i = 0;
141
142         FILE *f = fopen(path, "r");
143
144         if (f == NULL) {
145                 WAE_SLOGE("Failed to open a file. file=%s", path);
146                 return WAE_ERROR_FILE;
147         }
148
149         fseek(f, 0, SEEK_END); // move to the end of a file
150         int file_len = ftell(f);
151
152         if (file_len <= 0) {
153                 WAE_SLOGE("Failed to get file size by ftell. ret: %d", file_len);
154                 ret = WAE_ERROR_FILE;
155                 goto error;
156         }
157
158         fseek(f, 0, SEEK_SET); // move to the start of a file
159
160         data = buffer_create(file_len);
161         if (data == NULL) {
162                 WAE_SLOGE("Failed to allocate memory for encrypted_dek");
163                 ret = WAE_ERROR_MEMORY;
164                 goto error;
165         }
166
167         while ((ch = fgetc(f)) != EOF)
168                 data->buf[i++] = (char)ch;
169
170         *pdata = data;
171
172 error:
173         fclose(f);
174
175         if (ret != WAE_ERROR_NONE)
176                 buffer_destroy(data);
177
178         return ret;
179 }
180
181 int _get_preloaded_app_dek_file_path(const char *pkg_id, size_t size, char *path)
182 {
183         int ret = snprintf(path, size, "%s/%s_%s.adek",
184                                    _get_dek_store_path(), APP_DEK_FILE_PFX, pkg_id);
185
186         if (ret < 0)
187                 return WAE_ERROR_INVALID_PARAMETER; /* buffer size too small */
188
189         return WAE_ERROR_NONE;
190 }
191
192 static int _extract_pkg_id_from_file_name(const char *file_name, char *pkg_id)
193 {
194         char *start = strstr(file_name, APP_DEK_FILE_PFX);
195
196         if (start == NULL) {
197                 WAE_SLOGE("WAE: Fail to extract pkgid from APP_DEK file. file_name=%s", file_name);
198                 return WAE_ERROR_FILE;
199         }
200
201         start = start + strlen(APP_DEK_FILE_PFX) + 1;
202         char *end = strstr(file_name, ".adek");
203
204         if (start == NULL) {
205                 WAE_SLOGE("WAE: Fail to extract pkgid from APP_DEK file. file_name=%s", file_name);
206                 return WAE_ERROR_FILE;
207         }
208
209         strncpy(pkg_id, start, end - start);
210         pkg_id[end - start] = 0; //terminate string
211
212         return WAE_ERROR_NONE;
213 }
214
215 int _read_encrypted_app_dek_from_file(const char *pkg_id, raw_buffer_s **pencrypted)
216 {
217         char path[MAX_PATH_LEN] = {0,};
218         _get_preloaded_app_dek_file_path(pkg_id, sizeof(path), path);
219         return _read_from_file(path, pencrypted);
220 }
221
222 int _write_encrypted_app_dek_to_file(const char *pkg_id, const raw_buffer_s *encrypted)
223 {
224         char path[MAX_PATH_LEN] = {0,};
225         _get_preloaded_app_dek_file_path(pkg_id, sizeof(path), path);
226         return _write_to_file(path, encrypted);
227 }
228
229 int get_app_ce(const char *pkg_id, wae_app_type_e app_type, bool create_for_migrated_app,
230                            const crypto_element_s **pce)
231 {
232         if (pkg_id == NULL || pce == NULL)
233                 return WAE_ERROR_INVALID_PARAMETER;
234
235         const crypto_element_s *cached_ce = _get_app_ce_from_cache(pkg_id);
236         if (cached_ce != NULL) {
237                 WAE_SLOGD("cache hit of app ce for pkg_id(%s)", pkg_id);
238                 *pce = cached_ce;
239                 return WAE_ERROR_NONE;
240         }
241
242         WAE_SLOGD("cache miss of app ce for pkg_id(%s)", pkg_id);
243
244         crypto_element_s *ce = NULL;
245         int ret = get_from_key_manager(pkg_id, app_type, &ce);
246
247         if (create_for_migrated_app &&
248                         (ret == WAE_ERROR_NO_KEY && app_type == WAE_DOWNLOADED_GLOBAL_APP)) {
249                 WAE_SLOGI("No dek found for pkg_id(%s)! It should be migrated app.", pkg_id);
250
251                 if ((ret = get_old_ss_crypto_element(pkg_id, &ce)) != WAE_ERROR_NONE)
252                         goto error;
253
254                 // (k.tak) disable to save ce to key-maanger for migrated app because of permission issue.
255                 //ret = save_to_key_manager(pkg_id, app_type, ce);
256                 //if (ret != WAE_ERROR_NONE) {
257                 //      WAE_SLOGW("Failed to save migrated app ce to key-manager with ret(%d). "
258                 //                        "Ignore this error because we can create ce later again.", ret);
259                 //      ret = WAE_ERROR_NONE;
260                 //}
261         } else if (ret != WAE_ERROR_NONE) {
262                 WAE_SLOGE("Failed to get crypto element from key-manager. pkg_id=%s, ret=%d",
263                                   pkg_id, ret);
264                 goto error;
265         }
266
267         ret = _add_app_ce_to_cache(pkg_id, ce);
268         if (ret != WAE_ERROR_NONE) {
269                 WAE_SLOGE("Failed to add ce to cache for pkg_id(%s) ret(%d)", pkg_id, ret);
270                 goto error;
271         }
272
273         *pce = ce;
274
275         WAE_SLOGD("Successfully get ce! pkgid(%s)", pkg_id);
276
277         return WAE_ERROR_NONE;
278
279 error:
280         crypto_element_destroy(ce);
281
282         return ret;
283 }
284
285 int create_app_ce(const char *pkg_id, wae_app_type_e app_type, const crypto_element_s **pce)
286 {
287         raw_buffer_s *dek = buffer_create(DEK_LEN);
288         raw_buffer_s *iv = buffer_create(IV_LEN);
289         crypto_element_s *ce = crypto_element_create(dek, iv);
290
291         int ret = WAE_ERROR_NONE;
292
293         if (ce == NULL) {
294                 ret = WAE_ERROR_MEMORY;
295                 goto error;
296         }
297
298         memcpy(ce->iv->buf, AES_CBC_IV, ce->iv->size);
299
300         ret = _get_random(dek);
301         if (ret != WAE_ERROR_NONE) {
302                 WAE_SLOGE("Failed to get random for dek. pkg_id(%s) ret(%d)", pkg_id, ret);
303                 goto error;
304         }
305
306         ret = save_to_key_manager(pkg_id, app_type, ce);
307         if (ret != WAE_ERROR_NONE) {
308                 WAE_SLOGE("Failed to save ce to key-manager. pkg_id(%s) app_type(%d) ret(%d)",
309                                   pkg_id, app_type, ret);
310                 goto error;
311         }
312
313         ret = _add_app_ce_to_cache(pkg_id, ce);
314         if (ret != WAE_ERROR_NONE) {
315                 WAE_SLOGE("Failed to add ce to cache for pkg_id(%s) ret(%d)", pkg_id, ret);
316                 goto error;
317         }
318
319         *pce = ce;
320
321         WAE_SLOGI("Success to create dek/iv and store it in key-manager. pkg_id(%s)", pkg_id);
322
323         return WAE_ERROR_NONE;
324
325 error:
326         if (ce == NULL) {
327                 buffer_destroy(dek);
328                 buffer_destroy(iv);
329         } else {
330                 crypto_element_destroy(ce);
331         }
332
333         return ret;
334 }
335
336 int get_preloaded_app_ce(const char *pkg_id, const crypto_element_s **pce)
337 {
338         const crypto_element_s *cached_ce = _get_app_ce_from_cache(pkg_id);
339
340         if (cached_ce == NULL) {
341                 WAE_SLOGE("WAE: Fail to get APP_DEK from cache for preloaded app");
342                 return WAE_ERROR_NO_KEY;
343         }
344
345         *pce = cached_ce;
346
347         return WAE_ERROR_NONE;
348 }
349
350 int create_preloaded_app_ce(const char *pkg_id, const crypto_element_s **pce)
351 {
352         raw_buffer_s *encrypted_app_dek = NULL;
353         raw_buffer_s *pubkey = NULL;
354         raw_buffer_s *dek = buffer_create(DEK_LEN);
355         raw_buffer_s *iv = buffer_create(sizeof(AES_CBC_IV));
356         crypto_element_s *ce = crypto_element_create(dek, iv);
357
358         int ret = WAE_ERROR_NONE;
359
360         if (dek == NULL || iv == NULL || ce == NULL) {
361                 ret = WAE_ERROR_MEMORY;
362                 goto error;
363         }
364
365         ret = _get_random(dek);
366
367         if (ret != WAE_ERROR_NONE)
368                 goto error;
369
370         // copy default iv for preloaded app
371         memcpy(iv->buf, AES_CBC_IV, sizeof(AES_CBC_IV));
372
373         ret = _read_from_file(_get_dek_kek_pub_key_path(), &pubkey);
374
375         if (ret != WAE_ERROR_NONE) {
376                 WAE_SLOGE("WAE: Fail to read APP_DEK_KEK Public Key");
377                 goto error;
378         }
379
380         ret = encrypt_app_dek(pubkey, dek, &encrypted_app_dek);
381
382         if (ret != WAE_ERROR_NONE) {
383                 WAE_SLOGE("WAE: Fail to encrypt APP_DEK with APP_DEK_KEK");
384                 goto error;
385         }
386
387         // write APP_DEK in a file
388         ret = _write_encrypted_app_dek_to_file(pkg_id, encrypted_app_dek);
389
390         if (ret != WAE_ERROR_NONE) {
391                 WAE_SLOGE("Failed to write encrypted dek to file. pkg_id(%s)", pkg_id);
392                 goto error;
393         }
394
395         // store APP_DEK in cache
396         _add_app_ce_to_cache(pkg_id, ce);
397         if (ret != WAE_ERROR_NONE) {
398                 WAE_SLOGE("Failed to add ce to cache for pkg_id(%s) ret(%d)", pkg_id, ret);
399                 goto error;
400         }
401
402         *pce = ce;
403
404         WAE_SLOGI("Success to create preleaded dek and write it in initial value file. "
405                           "pkg_id(%s)", pkg_id);
406
407 error:
408         buffer_destroy(encrypted_app_dek);
409         buffer_destroy(pubkey);
410
411         if (ret != WAE_ERROR_NONE) {
412                 if (ce) {
413                         crypto_element_destroy(ce);
414                 } else {
415                         buffer_destroy(dek);
416                         buffer_destroy(iv);
417                 }
418         }
419
420         return ret;
421 }
422
423 int _get_app_dek_kek(raw_buffer_s **pdek_kek)
424 {
425 #if 0
426         return get_dek_kek_from_key_manager(pdek_kek);
427 #else
428         return _read_from_file(_get_dek_kek_pri_key_path(), pdek_kek);
429 #endif
430 }
431
432 int load_preloaded_app_deks(bool reload)
433 {
434         int ret = WAE_ERROR_NONE;
435
436         char pkg_id[MAX_PKGID_LEN] = {0, };
437
438         char file_path_buff[MAX_PATH_LEN];
439         raw_buffer_s *encrypted_dek = NULL;
440         raw_buffer_s *dek = NULL;
441         raw_buffer_s *iv = NULL;
442         raw_buffer_s *prikey = NULL;
443         crypto_element_s *ce = NULL;
444
445         int error_during_loading = 0;
446
447         if (!reload) {
448                 // check if all deks were already loaded into key-manager.
449                 ret = is_app_deks_loaded_in_key_manager();
450
451                 if (ret == WAE_ERROR_NONE)
452                         return ret;
453         }
454
455         ret = _get_app_dek_kek(&prikey);
456
457         if (ret != WAE_ERROR_NONE) {
458                 WAE_SLOGE("Fail to get APP_DEK_KEK Private Key");
459                 return ret;
460         }
461
462         DIR *dir = opendir(_get_dek_store_path());
463
464         if (dir == NULL) {
465                 WAE_SLOGE("Fail to open dir. dir=%s", _get_dek_store_path());
466                 return WAE_ERROR_FILE;
467         }
468
469         struct dirent entry;
470         struct dirent *result = NULL;
471
472         while (true) {
473                 int error = readdir_r(dir, &entry, &result);
474
475                 if (error != 0) {
476                         ret = WAE_ERROR_FILE;
477                         goto error;
478                 }
479
480                 // readdir_r returns NULL in *result if the end
481                 // of the directory stream is reached
482                 if (result == NULL)
483                         break;
484
485                 // regular file && start with KEY_MANAGER_INITIAL_VALUE_FILE_PFX
486                 if (entry.d_type != DT_REG || strstr(entry.d_name, APP_DEK_FILE_PFX) == NULL)
487                         continue;
488
489                 ret = snprintf(file_path_buff, sizeof(file_path_buff), "%s/%s",
490                                            _get_dek_store_path(), entry.d_name);
491
492                 if (ret < 0) {
493                         WAE_SLOGE("Failed to make file path by snprintf.");
494                         ret = WAE_ERROR_INVALID_PARAMETER; /* buffer size too small */
495                         goto error;
496                 }
497
498                 ret = _extract_pkg_id_from_file_name(entry.d_name, pkg_id);
499
500                 if (ret != WAE_ERROR_NONE) {
501                         WAE_SLOGW("Failed to extract pkgid from file. It will be ignored. file=%s",
502                                           file_path_buff);
503                         continue;
504                 }
505
506                 ret = _read_from_file(file_path_buff, &encrypted_dek);
507
508                 if (ret != WAE_ERROR_NONE || encrypted_dek == NULL) {
509                         ++error_during_loading;
510                         WAE_SLOGW("Failed to read file. It will be ignored. file=%s", file_path_buff);
511                         continue;
512                 }
513
514                 ret = decrypt_app_dek(prikey, APP_DEK_KEK_PRIKEY_PASSWORD, encrypted_dek, &dek);
515
516                 buffer_destroy(encrypted_dek);
517                 encrypted_dek = NULL;
518
519                 if (ret != WAE_ERROR_NONE || dek == NULL) {
520                         ++error_during_loading;
521                         WAE_SLOGW("Failed to decrypt dek. It will be ignored. file=%s",
522                                           file_path_buff);
523                         continue;
524                 }
525                 iv = buffer_create(IV_LEN);
526                 if (iv == NULL) {
527                         ++error_during_loading;
528                         buffer_destroy(dek);
529                         dek = NULL;
530                         continue;
531                 }
532
533                 memcpy(iv->buf, AES_CBC_IV, iv->size);
534
535                 ce = crypto_element_create(dek, iv);
536                 if (ce == NULL) {
537                         ++error_during_loading;
538                         buffer_destroy(iv);
539                         iv = NULL;
540                         buffer_destroy(dek);
541                         dek = NULL;
542                         continue;
543                 }
544
545                 ret = save_to_key_manager(pkg_id, WAE_PRELOADED_APP, ce);
546
547                 if (ret == WAE_ERROR_KEY_EXISTS) {
548                         WAE_SLOGI("Key Manager already has dek. It will be ignored. file=%s",
549                                           file_path_buff);
550                 } else if (ret != WAE_ERROR_NONE) {
551                         ++error_during_loading;
552                         WAE_SLOGW("Fail to add APP DEK to key-manager. file=%s", file_path_buff);
553                 }
554
555                 crypto_element_destroy(ce);
556                 ce = NULL;
557         }
558
559         ret = set_app_deks_loaded_to_key_manager();
560
561 error:
562         if (ret != WAE_ERROR_NONE) {
563                 if (ce) {
564                         crypto_element_destroy(ce);
565                 } else {
566                         buffer_destroy(dek);
567                         buffer_destroy(iv);
568                 }
569         }
570
571         buffer_destroy(prikey);
572         closedir(dir);
573
574         return ret;
575 }
576
577 int remove_app_ce(const char *pkg_id, wae_app_type_e app_type)
578 {
579         int ret = remove_from_key_manager(pkg_id, app_type);
580
581         if (ret != WAE_ERROR_NONE)
582                 WAE_SLOGE("Failed to remove app ce for pkg_id(%s) ret(%d)", pkg_id, ret);
583         else
584                 WAE_SLOGI("Success to remove app ce for pkg_id(%s)", pkg_id);
585
586         _remove_app_ce_from_cache(pkg_id);
587
588         return ret;
589 }