2 * Copyright (c) 2000 - 2015 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 a header for key manupulatation.
28 #include <ckmc/ckmc-manager.h>
30 #include "web_app_enc.h"
31 #include "key_handler.h"
32 #include "crypto_service.h"
34 #include <tzplatform_config.h>
36 #define APP_DEK_KEK_PRIKEY_PASSWORD "wae_appdek_kek_1q2w3e4r"
38 #define WRT_INSTALLER_LABEL "/User"
40 typedef struct _dek_cache_element{
41 char pkgId[MAX_PKGID_LEN];
42 unsigned char dek[DEK_LEN];
45 dek_cache_element APP_DEK_CACHE[MAX_CACHE_SIZE];
46 int NEXT_CACHE_IDX = -1;
48 void _initialize_cache()
51 memset(APP_DEK_CACHE, 0, sizeof(dek_cache_element)*MAX_CACHE_SIZE);
54 unsigned char* _get_app_dek_from_cache(const char* pkgId)
58 if(NEXT_CACHE_IDX < 0)
61 for(i =0; i<MAX_CACHE_SIZE; i++) {
62 //WAE_SLOGI("CACHED APP_DEK[%d]=%s", i, APP_DEK_CACHE[i].pkgId);
63 if( strlen(APP_DEK_CACHE[i].pkgId) == strlen(pkgId) &&
64 strncmp(pkgId, APP_DEK_CACHE[i].pkgId, strlen(pkgId)) == 0) {
65 return APP_DEK_CACHE[i].dek;
71 void _add_app_dek_to_cache(const char* pkgId, unsigned char* dek)
75 if(NEXT_CACHE_IDX < 0)
78 // if existing one has the same pkgid
79 for(i =0; i<MAX_CACHE_SIZE; i++) {
80 if( strlen(APP_DEK_CACHE[i].pkgId) == strlen(pkgId) &&
81 strncmp(pkgId, APP_DEK_CACHE[i].pkgId, strlen(pkgId)) == 0) {
82 memcpy(APP_DEK_CACHE[i].dek, dek, DEK_LEN);
88 strncpy(APP_DEK_CACHE[NEXT_CACHE_IDX].pkgId, pkgId, strlen(pkgId));
89 memcpy(APP_DEK_CACHE[NEXT_CACHE_IDX].dek, dek, DEK_LEN);
92 if(NEXT_CACHE_IDX >= MAX_CACHE_SIZE)
96 void _remove_app_dek_from_cache(const char* pkgId)
100 for(i =0; i<MAX_CACHE_SIZE; i++) {
101 if( strlen(APP_DEK_CACHE[i].pkgId) == strlen(pkgId) &&
102 strncmp(pkgId, APP_DEK_CACHE[i].pkgId, strlen(pkgId)) == 0) {
103 memset(APP_DEK_CACHE[i].pkgId, 0, sizeof(APP_DEK_CACHE[i].pkgId));
110 int _to_wae_error(int key_manager_error)
112 switch(key_manager_error) {
113 case CKMC_ERROR_NONE: return WAE_ERROR_NONE;
114 case CKMC_ERROR_INVALID_PARAMETER: return WAE_ERROR_INVALID_PARAMETER;
115 case CKMC_ERROR_PERMISSION_DENIED: return WAE_ERROR_PERMISSION_DENIED;
116 case CKMC_ERROR_DB_ALIAS_UNKNOWN: return WAE_ERROR_NO_KEY;
117 case CKMC_ERROR_DB_ALIAS_EXISTS: return WAE_ERROR_KEY_EXISTS;
118 default: return WAE_ERROR_KEY_MANAGER;
122 int _get_random(size_t length, unsigned char* random)
128 if((f = fopen(RANDOM_FILE, "r")) != NULL){
130 if((ch = fgetc(f)) == EOF){
133 random[i] = (unsigned char) ch;
139 return WAE_ERROR_NONE;
142 void _get_alias(const char* pPkgId, wae_app_type_e appType, int forSave, char* alias, size_t buff_len)
144 if(appType == WAE_DOWNLOADED_NORMAL_APP) {
145 if(forSave == WAE_TRUE) {
146 snprintf(alias, buff_len, "%s%s",
150 snprintf(alias, buff_len, "%s%s%s%s",
152 ckmc_owner_id_separator,
156 }else { // system alias
158 snprintf(alias, buff_len, "%s%s%s%s",
159 ckmc_owner_id_system,
160 ckmc_owner_id_separator,
166 void _get_dek_kek_alias(char* alias, size_t buff_len)
168 snprintf(alias, buff_len, "%s%s%s",
169 ckmc_owner_id_system,
170 ckmc_owner_id_separator,
174 void _get_dek_loading_done_alias(char* alias, size_t buff_len)
176 snprintf(alias, buff_len, "%s%s%s",
177 ckmc_owner_id_system,
178 ckmc_owner_id_separator,
179 APP_DEK_LOADING_DONE_ALIAS);
182 const char* _get_dek_kek_pub_key_path()
184 return tzplatform_mkpath4(TZ_SYS_SHARE, "wae", "app_dek", "WAE_APPDEK_KEK_PublicKey.pem");
187 const char* _get_dek_kek_pri_key_path()
189 return tzplatform_mkpath4(TZ_SYS_SHARE, "wae", "app_dek", "WAE_APPDEK_KEK_PrivateKey.pem");
192 const char* _get_dek_store_path()
194 return tzplatform_mkpath3(TZ_SYS_SHARE, "wae", "app_dek");
197 int _add_dek_to_key_manager(const char* pPkgId, wae_app_type_e appType, const unsigned char* pDek, size_t len)
199 int ret = WAE_ERROR_NONE;
200 char alias[MAX_ALIAS_LEN] = {0,};
201 ckmc_raw_buffer_s buff;
202 ckmc_policy_s policy;
204 buff.data = (unsigned char *)pDek;
207 policy.password = NULL;
208 policy.extractable = true;
210 // save app_dek in key_manager
211 _get_alias(pPkgId, appType, WAE_TRUE, alias, sizeof(alias));
213 // even if it fails to remove, ignore it.
214 ret = _to_wae_error( ckmc_remove_alias(alias));
216 ret = _to_wae_error(ckmc_save_data(alias, buff, policy));
217 if(ret != WAE_ERROR_NONE) {
218 WAE_SLOGE("WAE: Fail to add APP_DEK to key-manager. pkgId=%s, alias=%s, ret=%d", pPkgId, alias, ret);
222 // share app_dek for web app laucher to use app_dek
223 ret = _to_wae_error(ckmc_set_permission(alias, pPkgId, CKMC_PERMISSION_READ));
224 if(ret != WAE_ERROR_NONE) {
225 WAE_SLOGE("WAE: Fail to set_permission to APP_DEK. pkgId=%s, ret=%d", pPkgId, ret);
228 WAE_SLOGI("WAE: Success to add APP_DEK to key-manager. pkgId=%s, alias=%s", pPkgId, alias);
234 int _get_preloaded_app_dek_file_path(const char* pPkgId, char *path)
236 sprintf(path, "%s/%s_%s.adek", _get_dek_store_path(), APP_DEK_FILE_PFX, pPkgId);
237 return WAE_ERROR_NONE;
240 int _extract_pkg_id_from_file_name(const char* fileName, char* pkgId)
242 char* start = strstr(fileName, APP_DEK_FILE_PFX);
244 WAE_SLOGE("WAE: Fail to extract pkgid from APP_DEK file. fileName=%s", fileName);
245 return WAE_ERROR_FILE;
247 start = start + strlen(APP_DEK_FILE_PFX) + 1;
248 char* end = strstr(fileName, ".adek");
250 WAE_SLOGE("WAE: Fail to extract pkgid from APP_DEK file. fileName=%s", fileName);
251 return WAE_ERROR_FILE;
253 strncpy(pkgId, start, end-start);
254 pkgId[end-start] = 0;//terminate string
255 return WAE_ERROR_NONE;
258 int _read_encrypted_app_dek_from_file(const char* pPkgId, unsigned char** encrypted_app_dek, size_t *len)
260 char path[MAX_PATH_LEN] = {0,};
261 _get_preloaded_app_dek_file_path(pPkgId, path);
262 return _read_from_file(path, encrypted_app_dek, len);
265 int _write_encrypted_app_dek_to_file(const char* pPkgId, const unsigned char* encrypted_app_dek, size_t len)
267 char path[MAX_PATH_LEN] = {0,};
268 _get_preloaded_app_dek_file_path(pPkgId, path);
269 return _write_to_file( path, encrypted_app_dek, len);
272 int _read_from_file(const char* path, unsigned char** data, size_t* len)
274 int ret = WAE_ERROR_NONE;
277 unsigned char* file_contents = NULL;
281 f = fopen(path, "r");
283 WAE_SLOGE("WAE: Fail to open a file. file=%s", path);
284 ret = WAE_ERROR_FILE;
288 fseek(f, 0, SEEK_END); // move to the end of a file
290 fseek(f, 0, SEEK_SET); // move to the start of a file
292 file_contents = (unsigned char*) malloc(file_len);
293 if(file_contents == NULL) {
294 WAE_SLOGE("WAE: Fail to allocate memory for encrypted_app_dek");
295 ret = WAE_ERROR_MEMORY;
298 memset(file_contents, 0x00, file_len);
300 while( (ch = fgetc(f)) != EOF) {
301 file_contents[i++]=(char)ch;
304 *data = file_contents;
310 if(ret != WAE_ERROR_NONE && file_contents != NULL)
316 int _write_to_file(const char* path, const unsigned char* data, size_t len)
318 int ret = WAE_ERROR_NONE;
323 f = fopen(path, "w");
325 WAE_SLOGE("WAE: Fail to open a file. file=%s", path);
326 ret = WAE_ERROR_FILE;
330 write_len = fwrite(data, 1, len, f);
331 if(write_len != (int) len) {
332 WAE_SLOGE("WAE: Fail to write a file. file=%s", path);
333 ret = WAE_ERROR_FILE;
343 int get_app_dek(const char* pPkgId, wae_app_type_e appType, unsigned char** ppDek, size_t* dekLen)
345 int ret = WAE_ERROR_NONE;
347 char* password = NULL;
348 ckmc_raw_buffer_s *pDekBuffer = NULL;
349 char alias[MAX_ALIAS_LEN] = {0,};
350 unsigned char* pDek = NULL;
351 unsigned char* cached_dek = NULL;
353 // get dek from cache
354 cached_dek = _get_app_dek_from_cache(pPkgId);
355 if(cached_dek == NULL) {
356 // get APP_DEK from system database
357 _get_alias(pPkgId, appType, WAE_FALSE, alias, sizeof(alias));
359 ret = _to_wae_error(ckmc_get_data(alias, password, &pDekBuffer));
360 if(ret != WAE_ERROR_NONE) {
361 WAE_SLOGI("WAE: Fail to get APP_DEK from key-manager. pkgId=%s, alias=%s, ret=%d",
367 pDek = (unsigned char*) malloc(DEK_LEN);
369 WAE_SLOGE("Fail to allocate a memory");
370 ret = WAE_ERROR_MEMORY;
373 memcpy(pDek, (cached_dek != NULL) ? cached_dek : pDekBuffer->data, DEK_LEN);
377 WAE_SLOGI("WAE: Success to get APP_DEK from key-manager. pkgId=%s, alias=%s", pPkgId, alias);
379 if(pDekBuffer != NULL)
380 ckmc_buffer_free(pDekBuffer);
381 if(ret != WAE_ERROR_NONE && pDek != NULL)
387 int create_app_dek(const char* pPkgId, wae_app_type_e appType, unsigned char** ppDek, size_t* dekLen)
389 int ret = WAE_ERROR_NONE;
390 unsigned char *dek= NULL;
392 dek = (unsigned char*) malloc(DEK_LEN);
394 ret = WAE_ERROR_MEMORY;
398 ret = _get_random(DEK_LEN, dek);
399 if(ret != WAE_ERROR_NONE) {
400 WAE_SLOGE("WAE: Fail to get random for APP_DEK. pkgId=%s, ret=%d", pPkgId, ret);
404 // save app_dek in key_manager
405 ret = _add_dek_to_key_manager(pPkgId, appType, dek, DEK_LEN);
406 if(ret != WAE_ERROR_NONE) {
410 // store APP_DEK in cache
411 _add_app_dek_to_cache(pPkgId, dek);
416 WAE_SLOGI("WAE: Success to create APP_DEK and store it in key-manager. pkgId=%s", pPkgId);
418 if(ret != WAE_ERROR_NONE && dek != NULL)
424 int get_preloaded_app_dek(const char* pPkgId, unsigned char** ppDek, size_t* dekLen)
426 int ret = WAE_ERROR_NONE;
427 unsigned char* cached_dek= NULL;
428 unsigned char* dek = NULL;
430 // get dek from cache
431 cached_dek = _get_app_dek_from_cache(pPkgId);
432 if(cached_dek == NULL) {
433 WAE_SLOGE("WAE: Fail to get APP_DEK from cache for preloaded app");
434 ret = WAE_ERROR_NO_KEY;
438 dek = (unsigned char*) malloc(DEK_LEN);
440 WAE_SLOGE("WAE: Fail to allocate memory for preloaded app dek");
441 ret = WAE_ERROR_MEMORY;
444 memcpy(dek, cached_dek, DEK_LEN);
449 if(ret != WAE_ERROR_NONE && dek != NULL)
455 int create_preloaded_app_dek(const char* pPkgId, unsigned char** ppDek, size_t* dekLen)
457 int ret = WAE_ERROR_NONE;
458 unsigned char* dek = NULL;
459 unsigned char* encrypted_app_dek = NULL;
460 size_t encrypted_app_dek_len = 0;
461 unsigned char* pubKey = NULL;
462 size_t pubKeyLen = 0;
465 dek = (unsigned char*) malloc(DEK_LEN);
467 ret = WAE_ERROR_MEMORY;
471 ret = _get_random(DEK_LEN, dek);
472 if(ret != WAE_ERROR_NONE) {
476 // encrypt APP_DEK with APP_DEK_KEK
477 ret = _read_from_file(_get_dek_kek_pub_key_path(), &pubKey, &pubKeyLen);
478 if(ret != WAE_ERROR_NONE) {
479 WAE_SLOGE("WAE: Fail to read APP_DEK_KEK Public Key");
483 ret = encrypt_app_dek(pubKey, pubKeyLen, dek, DEK_LEN, &encrypted_app_dek, &encrypted_app_dek_len);
484 if(ret != WAE_ERROR_NONE) {
485 WAE_SLOGE("WAE: Fail to encrypt APP_DEK with APP_DEK_KEK");
489 // write APP_DEK in a file
490 ret = _write_encrypted_app_dek_to_file(pPkgId, encrypted_app_dek, encrypted_app_dek_len);
491 if(ret != WAE_ERROR_NONE) {
492 WAE_SLOGE("WAE: Fail to write encrypted APP_DEK. pkgId=%s", pPkgId);
496 // store APP_DEK in cache
497 _add_app_dek_to_cache(pPkgId, dek);
501 WAE_SLOGI("WAE: Success to create preleaded APP_DEK and write it in initail value file. pkgId=%s", pPkgId);
506 if(encrypted_app_dek != NULL)
507 free(encrypted_app_dek);
508 if(ret != WAE_ERROR_NONE && dek != NULL)
514 int _get_app_dek_kek(unsigned char** ppDekKek, size_t* kekLen)
516 int ret = WAE_ERROR_NONE;
518 ret = _read_from_file(_get_dek_kek_pri_key_path(), ppDekKek, kekLen);
519 if(ret != WAE_ERROR_NONE) {
520 WAE_SLOGE("WAE: Fail to read APP_DEK_KEK Private Key");
524 char* password = NULL;
525 ckmc_raw_buffer_s *pKekBuffer = NULL;
526 unsigned char* pKek = NULL;
528 char dek_kek_alias[MAX_ALIAS_LEN] = {0, };
529 _get_dek_kek_alias(dek_kek_alias, sizeof(dek_kek_alias));
531 ret = _to_wae_error(ckmc_get_data(dek_kek_alias, password, &pKekBuffer));
532 if(ret != WAE_ERROR_NONE) {
533 WAE_SLOGE("Fail to get APP_DEK_KEK from key-manager. alias=%s, ret=%d", APP_DEK_KEK_ALIAS, ret);
537 pKek = (unsigned char*) malloc(pKekBuffer->size);
539 WAE_SLOGE("Fail to allocate a memory");
540 ret = WAE_ERROR_MEMORY;
543 memcpy(pKek, pKekBuffer->data, pKekBuffer->size);
546 *kekLen = pKekBuffer->size;
547 WAE_SLOGI("Success to get APP_DEK_KEK from key-manager.");
549 if(pKekBuffer != NULL)
550 ckmc_buffer_free(pKekBuffer);
551 if(ret != WAE_ERROR_NONE && pKek != NULL)
558 int _get_app_deks_loaded()
560 int ret = WAE_ERROR_NONE;
562 ckmc_raw_buffer_s *pBuffer = NULL;
563 char loading_done_alias[MAX_ALIAS_LEN] = {0, };
565 _get_dek_loading_done_alias(loading_done_alias, sizeof(loading_done_alias));
567 ret = _to_wae_error(ckmc_get_data(loading_done_alias, NULL, &pBuffer));
568 if(ret == WAE_ERROR_NO_KEY) {
569 WAE_SLOGI("WAE: APP_DEK_LOADING was not done");
570 } else if(ret == WAE_ERROR_NONE) {
571 WAE_SLOGI("WAE: APP_DEK_LOADING was already done");
573 WAE_SLOGE("WAE: Fail to get information from key-manager about APP_DEK_LOADING_DONE_ALIAS. ret=%d", ret);
579 ckmc_buffer_free(pBuffer);
584 int _set_app_deks_loaded()
586 int ret = WAE_ERROR_NONE;
587 ckmc_raw_buffer_s buff;
588 ckmc_policy_s policy;
589 unsigned char dummyData[1] = {0};
591 buff.data = dummyData;
592 buff.size = sizeof(dummyData);
594 policy.password = NULL;
595 policy.extractable = true;
597 char loading_done_alias[MAX_ALIAS_LEN] = {0, };
598 _get_dek_loading_done_alias(loading_done_alias, sizeof(loading_done_alias));
600 ret = _to_wae_error(ckmc_save_data(loading_done_alias, buff, policy));
601 if(ret == WAE_ERROR_KEY_EXISTS) {
602 WAE_SLOGI("WAE: APP_DEK_LOADING was already done");
603 ret = WAE_ERROR_NONE;
604 } else if(ret != WAE_ERROR_NONE) {
605 WAE_SLOGE("WAE: Fail to set APP_DEK_LOADING_DONE_ALIAS to key-manager. ret=%d", ret);
609 WAE_SLOGI("Success to set APP_DEK_LOADING_DONE_ALIAS to key-manager.");
614 int _clear_app_deks_loaded()
616 int ret = WAE_ERROR_NONE;
617 char loading_done_alias[MAX_ALIAS_LEN] = {0, };
618 _get_dek_loading_done_alias(loading_done_alias, sizeof(loading_done_alias));
620 ret = _to_wae_error(ckmc_remove_alias(loading_done_alias));
621 if(ret == WAE_ERROR_NO_KEY) {
622 WAE_SLOGI("APP_DEK_LOADING_DONE_ALIAS was not set to key-manager before.");
623 ret = WAE_ERROR_NONE;
624 }else if(ret != WAE_ERROR_NONE) {
625 WAE_SLOGE("Fail to clear APP_DEK_LOADING_DONE_ALIAS to key-manager. ret=%d", ret);
631 int load_preloaded_app_deks(int reload)
633 int ret = WAE_ERROR_NONE;
635 char pkgId[MAX_PKGID_LEN] = {0, };
639 struct dirent *result;
641 char file_path_buff[MAX_PATH_LEN];
642 unsigned char* encrypted_app_dek = NULL;
643 size_t encrypted_app_dek_len = 0;
644 unsigned char* app_dek = NULL;
645 size_t app_dek_len = 0;
646 unsigned char* priKey = NULL;
647 size_t priKeyLen = 0;
649 int error_during_loading = 0;
651 if(reload != WAE_TRUE) {
652 // check if all deks were already loaded into key-manager.
653 ret = _get_app_deks_loaded();
654 if(ret == WAE_ERROR_NONE) {
659 ret = _get_app_dek_kek(&priKey, &priKeyLen);
660 if(ret != WAE_ERROR_NONE) {
661 WAE_SLOGE("Fail to get APP_DEK_KEK Private Key");
665 dir = opendir(_get_dek_store_path());
667 WAE_SLOGE("Fail to open dir. dir=%s", _get_dek_store_path());
668 ret = WAE_ERROR_FILE;
673 error = readdir_r(dir, &entry, &result);
675 ret = WAE_ERROR_FILE;
678 // readdir_r returns NULL in *result if the end
679 // of the directory stream is reached
683 // regular file && start with KEY_MANAGER_INITIAL_VALUE_FILE_PFX
684 if(entry.d_type == DT_REG && strstr(entry.d_name, APP_DEK_FILE_PFX) != NULL) {
685 memset(file_path_buff, 0, sizeof(file_path_buff));
686 sprintf(file_path_buff, "%s/%s", _get_dek_store_path(), entry.d_name);
688 ret = _extract_pkg_id_from_file_name(entry.d_name, pkgId);
689 if(ret != WAE_ERROR_NONE) {
690 WAE_SLOGW("Fail to extract pkgid from file. It will be ignored. file=%s",file_path_buff);
694 ret = _read_from_file(file_path_buff, &encrypted_app_dek, &encrypted_app_dek_len);
695 if(ret != WAE_ERROR_NONE || encrypted_app_dek == NULL) {
696 error_during_loading++;
697 WAE_SLOGW("Fail to read file. It will be ignored. file=%s",file_path_buff);
701 ret = decrypt_app_dek(priKey, priKeyLen, APP_DEK_KEK_PRIKEY_PASSWORD,
702 encrypted_app_dek, encrypted_app_dek_len,
703 &app_dek, &app_dek_len);
704 if(ret != WAE_ERROR_NONE || app_dek == NULL) {
705 error_during_loading++;
706 WAE_SLOGW("Fail to decrypt APP DEK. It will be ignored. file=%s",file_path_buff);
710 // save app_dek in key_manager
711 ret = _add_dek_to_key_manager(pkgId, WAE_PRELOADED_APP, app_dek, app_dek_len);
714 free(encrypted_app_dek);
716 encrypted_app_dek = NULL;
718 if(ret == WAE_ERROR_KEY_EXISTS) {
719 WAE_SLOGI("Key Manager already has APP_DEK. It will be ignored. file=%s",file_path_buff);
721 }else if(ret != WAE_ERROR_NONE) {
722 error_during_loading++;
723 WAE_SLOGW("Fail to add APP DEK to key-manager. file=%s",file_path_buff);
729 ret = _set_app_deks_loaded();
730 if(ret == WAE_ERROR_NONE) {
731 WAE_SLOGI("Success to load_preloaded_app_deks");
732 ret = WAE_ERROR_NONE;
734 WAE_SLOGW("Fail to _set_app_deks_loaded to key-manager. ret=%d", ret);
744 int remove_app_dek(const char* pPkgId, wae_app_type_e appType)
746 int ret = CKMC_ERROR_NONE;
747 char alias[MAX_ALIAS_LEN] = {0,};
749 _get_alias(pPkgId, appType, WAE_TRUE, alias,sizeof(alias));
751 ret = _to_wae_error(ckmc_remove_alias(alias));
752 if(ret != WAE_ERROR_NONE) {
753 WAE_SLOGE("Fail to remove APP_DEK from key-manager. pkgId=%s, alias=%s, ret=%d", pPkgId, alias, ret);
757 _remove_app_dek_from_cache(pPkgId);
758 WAE_SLOGI("Success to remove APP_DEK from key-manager. pkgId=%s", pPkgId);
760 return WAE_ERROR_NONE;