2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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
18 * @author Dongsun Lee (ds73.lee@samsung.com)
20 * @brief Key manupulatation.
22 #include "key_handler.h"
30 #include <tzplatform_config.h>
32 #include "web_app_enc.h"
34 #include "crypto_service.h"
35 #include "key_manager.h"
36 #include "decrypt_migrated_wgt.h"
38 #define RANDOM_FILE "/dev/urandom"
39 #define APP_DEK_KEK_PRIKEY_PASSWORD "wae_appdek_kek_1q2w3e4r"
40 #define APP_DEK_FILE_PFX "WAE_APP_DEK"
44 #define MAX_PKGID_LEN 256
45 #define MAX_CACHE_SIZE 100
47 static unsigned char AES_CBC_IV[IV_LEN] = {
48 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
49 0x08, 0x39, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
52 static crypto_element_map_s *_map;
54 static void deinit_lib(void) __attribute__((destructor));
55 static void deinit_lib(void)
57 crypto_element_map_destroy(_map);
60 char *_create_map_key(uid_t uid, const char *pkg_id)
64 int ret = asprintf(&key, "%u-%s", uid, pkg_id);
66 return (ret == -1) ? NULL : key;
69 static const crypto_element_s *_get_app_ce_from_cache(const char *key)
71 return crypto_element_map_get(_map, key);
74 static int _add_app_ce_to_cache(const char *key, crypto_element_s *ce)
76 return crypto_element_map_add(&_map, key, ce);
79 void _remove_app_ce_from_cache(const char *key)
81 crypto_element_map_remove(&_map, key);
84 int _get_random(raw_buffer_s *rb)
86 if (!is_buffer_valid(rb))
87 return WAE_ERROR_INVALID_PARAMETER;
89 FILE *f = fopen(RANDOM_FILE, "r");
92 WAE_SLOGE("Failed to open random file source: %s", RANDOM_FILE);
93 return WAE_ERROR_FILE;
98 while (i < rb->size && (ch = fgetc(f) != EOF))
99 rb->buf[i++] = (unsigned char)ch;
103 return WAE_ERROR_NONE;
106 const char *_get_dek_kek_pub_key_path()
108 return tzplatform_mkpath4(TZ_SYS_SHARE, "wae", "app_dek", "WAE_APPDEK_KEK_PublicKey.pem");
111 const char *_get_dek_kek_pri_key_path()
113 return tzplatform_mkpath4(TZ_SYS_SHARE, "wae", "app_dek", "WAE_APPDEK_KEK_PrivateKey.pem");
116 const char *_get_dek_store_path()
118 return tzplatform_mkpath3(TZ_SYS_SHARE, "wae", "app_dek");
121 static int _write_to_file(const char *path, const raw_buffer_s *data)
123 if (path == NULL || !is_buffer_valid(data))
124 return WAE_ERROR_INVALID_PARAMETER;
126 FILE *f = fopen(path, "w");
129 WAE_SLOGE("Failed to open a file(%s)", path);
130 return WAE_ERROR_FILE;
133 int write_len = fwrite(data->buf, 1, data->size, f);
137 if (write_len != (int)data->size) {
138 WAE_SLOGE("Failed to write a file(%s)", path);
139 return WAE_ERROR_FILE;
142 return WAE_ERROR_NONE;
145 static int _read_from_file(const char *path, raw_buffer_s **pdata)
147 int ret = WAE_ERROR_NONE;
148 raw_buffer_s *data = NULL;
152 FILE *f = fopen(path, "r");
155 WAE_SLOGE("Failed to open a file. file=%s", path);
156 return WAE_ERROR_FILE;
159 fseek(f, 0, SEEK_END); // move to the end of a file
160 int file_len = ftell(f);
163 WAE_SLOGE("Failed to get file size by ftell. ret: %d", file_len);
164 ret = WAE_ERROR_FILE;
168 fseek(f, 0, SEEK_SET); // move to the start of a file
170 data = buffer_create(file_len);
172 WAE_SLOGE("Failed to allocate memory for encrypted_dek");
173 ret = WAE_ERROR_MEMORY;
177 while ((ch = fgetc(f)) != EOF)
178 data->buf[i++] = (char)ch;
185 if (ret != WAE_ERROR_NONE)
186 buffer_destroy(data);
191 typedef int(*entry_callback)(const char *path, const struct dirent *entry, void *user_data);
192 static int traverse_directory(const char *path, entry_callback ecb, void *user_data)
194 DIR *dir = opendir(path);
196 if (errno == ENOENT) {
197 // it's not error for current cases of using traverse_directory.
198 // To open dek store directory for load/remove can be occured in some
199 // exception(or attacked) cases but we can just ignore it if it isn't the
200 // first time call load_preloaded_app_deks.
201 WAE_SLOGI("directory isn't exist(%s).", path);
202 return WAE_ERROR_NONE;
204 WAE_SLOGE("Failed to open dir(%s)", path);
205 return WAE_ERROR_FILE;
209 int ret = WAE_ERROR_NONE;
211 struct dirent *result = NULL;
213 if (readdir_r(dir, &entry, &result) != 0) {
214 WAE_SLOGE("readdir_r error on dir(%s) errno(%d)", path, errno);
216 } else if (result == NULL) {
217 break; // end of directory
218 } else if (strcmp(entry.d_name, ".") == 0 || strcmp(entry.d_name, "..") == 0) {
222 int _ret = ecb(path, result, user_data);
223 if (_ret != WAE_ERROR_NONE)
231 static void _remove_file(const char *path)
236 static int _entry_callback_remove_all(
237 const char *path, const struct dirent *entry, void *user_data)
239 (void) user_data; // TODO: use UNUSED macro
241 char file_path_buff[MAX_PATH_LEN] = {0, };
242 if (snprintf(file_path_buff, sizeof(file_path_buff), "%s/%s", path, entry->d_name) < 0)
243 return WAE_ERROR_INVALID_PARAMETER; /* buffer size too small */
245 int ret = WAE_ERROR_NONE;
246 if (entry->d_type == DT_DIR) {
247 int _ret = traverse_directory(file_path_buff, _entry_callback_remove_all, NULL);
248 if (_ret != WAE_ERROR_NONE)
250 rmdir(file_path_buff);
252 _remove_file(file_path_buff);
257 void _remove_directory(const char *path)
259 traverse_directory(path, _entry_callback_remove_all, NULL);
261 WAE_SLOGD("remove directory(%s)", path);
265 int _get_preloaded_app_dek_file_path(const char *pkg_id, size_t size, char *path)
267 if (snprintf(path, size, "%s/%s_%s.adek",
268 _get_dek_store_path(), APP_DEK_FILE_PFX, pkg_id) < 0)
269 return WAE_ERROR_INVALID_PARAMETER; /* buffer size too small */
271 return WAE_ERROR_NONE;
274 static int _extract_pkg_id_from_file_name(const char *file_name, char *pkg_id)
276 char *start = strstr(file_name, APP_DEK_FILE_PFX);
279 WAE_SLOGE("WAE: Fail to extract pkgid from APP_DEK file. file_name=%s", file_name);
280 return WAE_ERROR_FILE;
283 start = start + strlen(APP_DEK_FILE_PFX) + 1;
284 char *end = strstr(file_name, ".adek");
287 WAE_SLOGE("WAE: Fail to extract pkgid from APP_DEK file. file_name=%s", file_name);
288 return WAE_ERROR_FILE;
291 strncpy(pkg_id, start, end - start);
292 pkg_id[end - start] = 0; //terminate string
294 return WAE_ERROR_NONE;
297 int _read_encrypted_app_dek_from_file(const char *pkg_id, raw_buffer_s **pencrypted)
299 char path[MAX_PATH_LEN] = {0,};
300 _get_preloaded_app_dek_file_path(pkg_id, sizeof(path), path);
301 return _read_from_file(path, pencrypted);
304 int _write_encrypted_app_dek_to_file(const char *pkg_id, const raw_buffer_s *encrypted)
306 char path[MAX_PATH_LEN] = {0,};
307 _get_preloaded_app_dek_file_path(pkg_id, sizeof(path), path);
308 return _write_to_file(path, encrypted);
311 int _load_preloaded_app_dek(
312 const raw_buffer_s *prikey, const char *filepath, const char *pkg_id)
314 raw_buffer_s *encrypted_dek = NULL;
315 raw_buffer_s *dek = NULL;
316 raw_buffer_s *iv = NULL;
317 crypto_element_s *ce = NULL;
319 int ret = _read_from_file(filepath, &encrypted_dek);
320 if (ret != WAE_ERROR_NONE) {
321 WAE_SLOGW("Failed to read file. It will be ignored. file=%s", filepath);
325 ret = decrypt_app_dek(prikey, APP_DEK_KEK_PRIKEY_PASSWORD, encrypted_dek, &dek);
326 if (ret != WAE_ERROR_NONE) {
327 WAE_SLOGW("Failed to decrypt dek. It will be ignored. file=%s", filepath);
331 iv = buffer_create(IV_LEN);
333 ret = WAE_ERROR_MEMORY;
337 memcpy(iv->buf, AES_CBC_IV, iv->size);
339 ce = crypto_element_create(dek, iv);
341 ret = WAE_ERROR_MEMORY;
345 ret = save_to_key_manager(pkg_id, pkg_id, WAE_PRELOADED_APP, ce);
346 if (ret == WAE_ERROR_KEY_EXISTS) {
347 WAE_SLOGI("Key Manager already has dek. It will be ignored. file=%s", filepath);
348 } else if (ret != WAE_ERROR_NONE) {
349 WAE_SLOGW("Fail to add APP DEK to key-manager. file=%s", filepath);
353 buffer_destroy(encrypted_dek);
359 crypto_element_destroy(ce);
365 int get_app_ce(uid_t uid, const char *pkg_id, wae_app_type_e app_type,
366 bool create_for_migrated_app, const crypto_element_s **pce)
368 if (pkg_id == NULL || pce == NULL)
369 return WAE_ERROR_INVALID_PARAMETER;
371 if (uid == 0 && app_type == WAE_DOWNLOADED_NORMAL_APP)
372 return WAE_ERROR_INVALID_PARAMETER;
374 const char *key = NULL;
375 char *_key_per_user = NULL;
377 if (app_type == WAE_DOWNLOADED_NORMAL_APP) {
378 _key_per_user = _create_map_key(uid, pkg_id);
379 if (_key_per_user == NULL)
380 return WAE_ERROR_MEMORY;
387 int ret = WAE_ERROR_NONE;
388 const crypto_element_s *cached_ce = _get_app_ce_from_cache(key);
389 if (cached_ce != NULL) {
390 WAE_SLOGD("cache hit of app ce for key(%s)", key);
395 WAE_SLOGD("cache miss of app ce for key(%s)", key);
397 crypto_element_s *ce = NULL;
398 ret = get_from_key_manager(key, app_type, &ce);
400 if (create_for_migrated_app &&
401 (ret == WAE_ERROR_NO_KEY && app_type == WAE_DOWNLOADED_GLOBAL_APP)) {
402 WAE_SLOGI("No dek found for key(%s)! It should be migrated app.", key);
404 if ((ret = get_old_ss_crypto_element(key, &ce)) != WAE_ERROR_NONE)
407 // (k.tak) disable to save ce to key-maanger for migrated app because of permission issue.
408 //ret = save_to_key_manager(key, pkg_id, app_type, ce);
409 //if (ret != WAE_ERROR_NONE) {
410 // WAE_SLOGW("Failed to save migrated app ce to key-manager with ret(%d). "
411 // "Ignore this error because we can create ce later again.", ret);
412 // ret = WAE_ERROR_NONE;
414 } else if (ret != WAE_ERROR_NONE) {
415 WAE_SLOGE("Failed to get crypto element from key-manager. key(%s) ret(%d)",
420 ret = _add_app_ce_to_cache(key, ce);
421 if (ret != WAE_ERROR_NONE) {
422 WAE_SLOGE("Failed to add ce to cache for key(%s) ret(%d)", key, ret);
428 WAE_SLOGD("Successfully get ce! key(%s)", key);
433 if (ret != WAE_ERROR_NONE)
434 crypto_element_destroy(ce);
439 int create_app_ce(uid_t uid, const char *pkg_id, wae_app_type_e app_type,
440 const crypto_element_s **pce)
442 raw_buffer_s *dek = buffer_create(DEK_LEN);
443 raw_buffer_s *iv = buffer_create(IV_LEN);
444 crypto_element_s *ce = crypto_element_create(dek, iv);
446 int ret = WAE_ERROR_NONE;
447 const char *key = NULL;
448 char *_key_per_user = NULL;
451 ret = WAE_ERROR_MEMORY;
455 if (app_type == WAE_DOWNLOADED_NORMAL_APP) {
456 _key_per_user = _create_map_key(uid, pkg_id);
457 if (_key_per_user == NULL) {
458 ret = WAE_ERROR_MEMORY;
467 memcpy(ce->iv->buf, AES_CBC_IV, ce->iv->size);
469 ret = _get_random(dek);
470 if (ret != WAE_ERROR_NONE) {
471 WAE_SLOGE("Failed to get random for dek. key(%s) ret(%d)", key, ret);
475 ret = save_to_key_manager(key, pkg_id, app_type, ce);
476 if (ret != WAE_ERROR_NONE) {
477 WAE_SLOGE("Failed to save ce to key-manager. key(%s) app_type(%d) ret(%d)",
482 ret = _add_app_ce_to_cache(key, ce);
483 if (ret != WAE_ERROR_NONE) {
484 WAE_SLOGE("Failed to add ce to cache for key(%s) ret(%d)", key, ret);
490 WAE_SLOGI("Success to create dek/iv and store it in key-manager. key(%s)", key);
493 if (ret != WAE_ERROR_NONE) {
498 crypto_element_destroy(ce);
507 int get_preloaded_app_ce(const char *pkg_id, const crypto_element_s **pce)
509 const crypto_element_s *cached_ce = _get_app_ce_from_cache(pkg_id);
511 if (cached_ce == NULL) {
512 WAE_SLOGE("WAE: Fail to get APP_DEK from cache for preloaded app");
513 return WAE_ERROR_NO_KEY;
518 return WAE_ERROR_NONE;
521 int create_preloaded_app_ce(const char *pkg_id, const crypto_element_s **pce)
523 raw_buffer_s *encrypted_app_dek = NULL;
524 raw_buffer_s *pubkey = NULL;
525 raw_buffer_s *dek = buffer_create(DEK_LEN);
526 raw_buffer_s *iv = buffer_create(sizeof(AES_CBC_IV));
527 crypto_element_s *ce = crypto_element_create(dek, iv);
529 int ret = WAE_ERROR_NONE;
531 if (dek == NULL || iv == NULL || ce == NULL) {
532 ret = WAE_ERROR_MEMORY;
536 ret = _get_random(dek);
538 if (ret != WAE_ERROR_NONE)
541 // copy default iv for preloaded app
542 memcpy(iv->buf, AES_CBC_IV, sizeof(AES_CBC_IV));
544 ret = _read_from_file(_get_dek_kek_pub_key_path(), &pubkey);
546 if (ret != WAE_ERROR_NONE) {
547 WAE_SLOGE("WAE: Fail to read APP_DEK_KEK Public Key");
551 ret = encrypt_app_dek(pubkey, dek, &encrypted_app_dek);
553 if (ret != WAE_ERROR_NONE) {
554 WAE_SLOGE("WAE: Fail to encrypt APP_DEK with APP_DEK_KEK");
558 // write APP_DEK in a file
559 ret = _write_encrypted_app_dek_to_file(pkg_id, encrypted_app_dek);
561 if (ret != WAE_ERROR_NONE) {
562 WAE_SLOGE("Failed to write encrypted dek to file. pkg_id(%s)", pkg_id);
566 // store APP_DEK in cache
567 ret = _add_app_ce_to_cache(pkg_id, ce);
568 if (ret != WAE_ERROR_NONE) {
569 WAE_SLOGE("Failed to add ce to cache for pkg_id(%s) ret(%d)", pkg_id, ret);
575 WAE_SLOGI("Success to create preleaded dek and write it in initial value file. "
576 "pkg_id(%s)", pkg_id);
579 buffer_destroy(encrypted_app_dek);
580 buffer_destroy(pubkey);
582 if (ret != WAE_ERROR_NONE) {
584 crypto_element_destroy(ce);
594 int _get_app_dek_kek(raw_buffer_s **pdek_kek)
597 return get_dek_kek_from_key_manager(pdek_kek);
599 return _read_from_file(_get_dek_kek_pri_key_path(), pdek_kek);
603 static int _entry_callback_load_preloaded_adeks(
604 const char *path, const struct dirent *entry, void *prikey)
606 const char *pub_key_path = _get_dek_kek_pub_key_path();
607 const char *pri_key_path = _get_dek_kek_pri_key_path();
609 char file_path_buff[MAX_PATH_LEN] = {0, };
610 if (snprintf(file_path_buff, sizeof(file_path_buff), "%s/%s", path, entry->d_name) < 0)
611 return WAE_ERROR_INVALID_PARAMETER; /* buffer size too small */
613 if (strcmp(file_path_buff, pub_key_path) == 0 ||
614 strcmp(file_path_buff, pri_key_path) == 0)
615 return WAE_ERROR_NONE; /* skip KEK files */
617 if (entry->d_type != DT_REG || strstr(entry->d_name, APP_DEK_FILE_PFX) == NULL) {
618 if (entry->d_type == DT_DIR)
620 "Invalid file in dek store(%s). Directory shouldn't be here.", path);
623 "Invalid file in dek store(%s). "
624 "Not regular file or prefix(%s) is invalid.", path, APP_DEK_FILE_PFX);
626 return WAE_ERROR_FILE;
629 char pkg_id[MAX_PKGID_LEN] = {0, };
630 int ret = _extract_pkg_id_from_file_name(entry->d_name, pkg_id);
631 if (ret != WAE_ERROR_NONE) {
632 WAE_SLOGW("Failed to extract pkgid from file(%s). It will be ignored.", file_path_buff);
636 ret = _load_preloaded_app_dek((raw_buffer_s *)prikey, file_path_buff, pkg_id);
637 if (ret == WAE_ERROR_NONE || ret == WAE_ERROR_KEY_EXISTS) {
638 WAE_SLOGI("Successfully load app dek(%s)", file_path_buff);
639 return WAE_ERROR_NONE;
641 WAE_SLOGW("Failed to load app dek(%s) ret(%d)", file_path_buff, ret);
646 int load_preloaded_app_deks()
648 WAE_SLOGI("load_preloaded_app_deks start");
650 int ret = WAE_ERROR_NONE;
652 const char *dek_store_path = _get_dek_store_path();
654 raw_buffer_s *prikey = NULL;
657 // check if all deks were already loaded into key-manager.
658 // TODO: instead of checking key-manager, check based on file existance
659 dir = opendir(dek_store_path);
661 if (errno == ENOENT) {
663 "dek store doesn't exist. "
664 "It might be loading preloaded app deks already done");
666 return WAE_ERROR_NONE;
668 WAE_SLOGE("Fail to open dir. dir=%s", dek_store_path);
669 ret = WAE_ERROR_FILE;
674 ret = _get_app_dek_kek(&prikey);
675 if (ret != WAE_ERROR_NONE) {
676 WAE_SLOGE("Fail to get APP_DEK_KEK Private Key. ret(%d)", ret);
680 // close dek store dir fd not to affect the traverse_directory call
684 ret = traverse_directory(dek_store_path, _entry_callback_load_preloaded_adeks, prikey);
685 if (ret != WAE_ERROR_NONE)
686 WAE_SLOGE("Fail when traverse dek store directory. ret(%d)", ret);
690 buffer_destroy(prikey);
695 // remove dek store after loade done even though it's partially failed
696 // because malware can still put the file in dek store if it still system service's
697 // ownership and they can break this logic by inserting any file to dek store path.
698 // If KEK private key is inserted to key-manager with initial-value feature, malware
699 // cannot insert/encrypt/decrypt app dek so it's fine on preloaded app security but
700 // if we handle errors related loading file, malware can at least occur webappenc
701 // initializer service failure.
702 _remove_directory(dek_store_path);
707 int remove_app_ce(uid_t uid, const char *pkg_id, wae_app_type_e app_type)
709 if (uid == 0 && app_type == WAE_DOWNLOADED_NORMAL_APP)
710 return WAE_ERROR_INVALID_PARAMETER;
712 const char *key = NULL;
713 char *_key_per_user = NULL;
715 if (app_type == WAE_DOWNLOADED_NORMAL_APP) {
716 _key_per_user = _create_map_key(uid, pkg_id);
717 if (_key_per_user == NULL)
718 return WAE_ERROR_MEMORY;
725 int ret = remove_from_key_manager(key, app_type);
727 if (ret != WAE_ERROR_NONE)
728 WAE_SLOGE("Failed to remove app ce for key(%s) ret(%d)", key, ret);
730 WAE_SLOGI("Success to remove app ce for key(%s)", key);
732 _remove_app_ce_from_cache(key);