1 /*
2  * Copyright (c) 2023-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *    http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "hks_upgrade_helper.h"
17 
18 #ifdef HKS_CONFIG_FILE
19 #include HKS_CONFIG_FILE
20 #else
21 #include "hks_config.h"
22 #endif
23 
24 #include "hks_check_trust_list.h"
25 #include "hks_client_service_util.h"
26 #include "hks_get_process_info.h"
27 #include "hks_log.h"
28 #include "hks_mem.h"
29 #include "hks_storage.h"
30 #include "hks_template.h"
31 #include "hks_type_inner.h"
32 
33 #include "hks_upgrade_key_accesser.h"
34 
35 #include "securec.h"
36 
37 #ifdef HKS_ENABLE_SMALL_TO_SERVICE
38 #define HKS_OLD_KEY_VERSION_FOR_SDK_HUKS 1
39 
HksIsProcessInfoInTrustList(const struct HksProcessInfo * processInfo)40 static int32_t HksIsProcessInfoInTrustList(const struct HksProcessInfo *processInfo)
41 {
42     uint32_t uid = 0;
43     if (processInfo->processName.size == sizeof(uid)) {
44         (void)memcpy_s(&uid, sizeof(uid), processInfo->processName.data, processInfo->processName.size);
45     } else {
46         return HKS_ERROR_NO_PERMISSION;
47     }
48 
49     return HksCheckIsInTrustList(uid);
50 }
51 
52 #ifdef HKS_ENABLE_MARK_CLEARED_FOR_SMALL_TO_SERVICE
53 // it is ok for no mutex lock, because the hugest problem it can lead to is checking key directory for nothing once
54 static volatile bool g_isOldKeyCleared = false;
55 
HksMarkOldKeyClearedIfEmpty(void)56 void HksMarkOldKeyClearedIfEmpty(void)
57 {
58     uint32_t keyCount = 0;
59     int32_t ret = HksIsOldKeyPathCleared(&keyCount);
60     if (ret == HKS_SUCCESS && keyCount == 0) {
61         // record mark
62         g_isOldKeyCleared = true;
63     }
64 }
65 
HksIsOldKeyCleared(void)66 static bool HksIsOldKeyCleared(void)
67 {
68     return g_isOldKeyCleared ? true : false;
69 }
70 #endif /** HKS_ENABLE_MARK_CLEARED_FOR_SMALL_TO_SERVICE */
71 
HksIsKeyExpectedVersion(const struct HksBlob * key,uint32_t expectedVersion)72 static int32_t HksIsKeyExpectedVersion(const struct HksBlob *key, uint32_t expectedVersion)
73 {
74     struct HksParam *keyVersion = NULL;
75     int32_t ret = HksGetParam((const struct HksParamSet *)key->data, HKS_TAG_KEY_VERSION, &keyVersion);
76     HKS_IF_NOT_SUCC_LOGE_RETURN(ret, ret, "get param key version failed!")
77     return (keyVersion->uint32Param == expectedVersion) ? HKS_SUCCESS : HKS_FAILURE;
78 }
79 
HksCheckNeedUpgradeForSmallToService(const struct HksProcessInfo * processInfo)80 int32_t HksCheckNeedUpgradeForSmallToService(const struct HksProcessInfo *processInfo)
81 {
82 #ifdef HKS_ENABLE_MARK_CLEARED_FOR_SMALL_TO_SERVICE
83     if (HksIsOldKeyCleared()) {
84         return HKS_FAILURE;
85     }
86 #endif
87     return HksIsProcessInfoInTrustList(processInfo);
88 }
89 
HksConstructRootProcessInfo(struct HksProcessInfo * processInfo)90 static int32_t HksConstructRootProcessInfo(struct HksProcessInfo *processInfo)
91 {
92     char *processName = NULL;
93     char *userId = NULL;
94     int32_t ret = HksGetProcessName(&processName);
95     HKS_IF_NOT_SUCC_LOGE_RETURN(ret, ret, "get old process name failed");
96     ret = HksGetUserId(&userId);
97     HKS_IF_NOT_SUCC_LOGE_RETURN(ret, ret, "get old user if failed");
98 
99     processInfo->processName.data = (uint8_t *)processName;
100     processInfo->processName.size = strlen(processName);
101     processInfo->userId.data = (uint8_t *)userId;
102     processInfo->userId.size = strlen(userId);
103     processInfo->userIdInt = 0;
104     processInfo->accessTokenId = 0;
105     return HKS_SUCCESS;
106 }
107 
HksDeleteOldKeyForSmallToService(const struct HksBlob * keyAlias)108 int32_t HksDeleteOldKeyForSmallToService(const struct HksBlob *keyAlias)
109 {
110     struct HksProcessInfo rootProcessInfo;
111     int32_t ret = HksConstructRootProcessInfo(&rootProcessInfo);
112     HKS_IF_NOT_SUCC_RETURN(ret, ret)
113     uint32_t keySize = 0;
114     ret = HksManageStoreGetKeyBlobSize(&rootProcessInfo, NULL, keyAlias, &keySize, HKS_STORAGE_TYPE_KEY);
115     HKS_IF_NOT_SUCC_LOGE_RETURN(ret, ret, "get keyblob size from storage failed, ret = %" LOG_PUBLIC "d.", ret)
116 
117     if (keySize > MAX_KEY_SIZE) {
118         HKS_LOG_E("invalid storage size, size = %" LOG_PUBLIC "u", keySize);
119         return HKS_ERROR_INVALID_KEY_FILE;
120     }
121     struct HksBlob oldKey = { .size = keySize, .data = NULL };
122     do {
123         oldKey.data = (uint8_t *)HksMalloc(keySize);
124         if (oldKey.data == NULL) {
125             ret = HKS_ERROR_MALLOC_FAIL;
126             break;
127         }
128         ret = HksManageStoreGetKeyBlob(&rootProcessInfo, NULL, keyAlias, &oldKey, HKS_STORAGE_TYPE_KEY);
129         HKS_IF_NOT_SUCC_BREAK(ret)
130         ret = HksIsKeyExpectedVersion(&oldKey, HKS_OLD_KEY_VERSION_FOR_SDK_HUKS);
131         if (ret != HKS_SUCCESS) {
132             ret = HKS_ERROR_NOT_EXIST;
133             break;
134         }
135 
136         ret = HksManageStoreDeleteKeyBlob(&rootProcessInfo, NULL, keyAlias, HKS_STORAGE_TYPE_KEY);
137         if ((ret != HKS_SUCCESS) && (ret != HKS_ERROR_NOT_EXIST)) {
138             HKS_LOG_E("service delete main key failed, ret = %" LOG_PUBLIC "d", ret);
139         }
140 
141 #ifdef HKS_ENABLE_MARK_CLEARED_FOR_SMALL_TO_SERVICE
142         HksMarkOldKeyClearedIfEmpty();
143 #endif
144     } while (0);
145     HKS_FREE_BLOB(oldKey);
146 
147     return ret;
148 }
149 
HksChangeKeyOwner(const struct HksProcessInfo * processInfo,const struct HksParamSet * paramSet,const struct HksBlob * keyAlias,enum HksStorageType mode)150 static int32_t HksChangeKeyOwner(const struct HksProcessInfo *processInfo, const struct HksParamSet *paramSet,
151     const struct HksBlob *keyAlias, enum HksStorageType mode)
152 {
153     HKS_LOG_I("enter HksChangeKeyOwner");
154     struct HksProcessInfo rootProcessInfo;
155     int32_t ret = HksConstructRootProcessInfo(&rootProcessInfo);
156     HKS_IF_NOT_SUCC_RETURN(ret, ret)
157 
158     struct HksBlob oldKey = { .size = 0, .data = NULL };
159     struct HksBlob newKey = { .size = 0, .data = NULL };
160 
161     struct HksParamSet *upgradeParamSet = NULL;
162 
163     do {
164         // get old key
165         ret = GetKeyFileData(&rootProcessInfo, NULL, keyAlias, &oldKey, mode);
166         HKS_IF_NOT_SUCC_LOGE_BREAK(ret, "not have old key")
167 
168         ret = ConstructUpgradeKeyParamSet(processInfo, paramSet, &upgradeParamSet);
169         HKS_IF_NOT_SUCC_LOGE_BREAK(ret, "construct param set failed!")
170         ret = HksIsKeyExpectedVersion(&oldKey, HKS_OLD_KEY_VERSION_FOR_SDK_HUKS);
171         if (ret != HKS_SUCCESS) {
172             ret = HKS_ERROR_NOT_EXIST;
173             break;
174         }
175 
176         newKey.data = (uint8_t *)HksMalloc(MAX_KEY_SIZE);
177         if (newKey.data == NULL) {
178             ret = HKS_ERROR_MALLOC_FAIL;
179             break;
180         }
181         newKey.size = MAX_KEY_SIZE;
182         ret = HksDoUpgradeKeyAccess(&oldKey, upgradeParamSet, &newKey);
183         HKS_IF_NOT_SUCC_LOGE_BREAK(ret, "access change key owner failed!")
184 
185         ret = HksManageStoreKeyBlob(processInfo, NULL, keyAlias, &newKey, HKS_STORAGE_TYPE_KEY);
186         HKS_IF_NOT_SUCC_LOGE_BREAK(ret, "store new key failed!")
187 
188         // delete old key only after new key stored successfully
189         (void)HksDeleteOldKeyForSmallToService(keyAlias);
190 
191 #ifdef HKS_ENABLE_MARK_CLEARED_FOR_SMALL_TO_SERVICE
192         HksMarkOldKeyClearedIfEmpty();
193 #endif
194     } while (0);
195     HksFreeParamSet(&upgradeParamSet);
196     HKS_FREE_BLOB(oldKey);
197     HKS_FREE_BLOB(newKey);
198 
199     return ret;
200 }
201 
HksChangeKeyOwnerForSmallToService(const struct HksProcessInfo * processInfo,const struct HksParamSet * paramSet,const struct HksBlob * keyAlias,enum HksStorageType mode)202 int32_t HksChangeKeyOwnerForSmallToService(const struct HksProcessInfo *processInfo, const struct HksParamSet *paramSet,
203     const struct HksBlob *keyAlias, enum HksStorageType mode)
204 {
205     HKS_LOG_I("enter get new key");
206     return HksChangeKeyOwner(processInfo, paramSet, keyAlias, mode);
207 }
208 
HksGetkeyInfoListByProcessName(const struct HksProcessInfo * processInfo,struct HksKeyInfo * keyInfoList,uint32_t * listCount)209 static int32_t HksGetkeyInfoListByProcessName(const struct HksProcessInfo *processInfo,
210     struct HksKeyInfo *keyInfoList, uint32_t *listCount)
211 {
212     int32_t ret;
213 
214     // the number for infos really added in keyInfoList
215     uint32_t realCnt = 0;
216     do {
217         ret = HksManageGetKeyAliasByProcessName(processInfo, NULL, keyInfoList, listCount);
218         HKS_IF_NOT_SUCC_LOGE_BREAK(ret, "get old key alias list from storage failed, ret = %" LOG_PUBLIC "d", ret)
219         for (uint32_t i = 0; i < *listCount; ++i) {
220             struct HksBlob keyFromFile = { 0, NULL };
221             ret = GetKeyFileData(processInfo, NULL, &(keyInfoList[i].alias), &keyFromFile, HKS_STORAGE_TYPE_KEY);
222             HKS_IF_NOT_SUCC_LOGE_BREAK(ret, "get old key data failed, ret = %" LOG_PUBLIC "d", ret)
223             if (HksIsKeyExpectedVersion(&keyFromFile, HKS_OLD_KEY_VERSION_FOR_SDK_HUKS) != HKS_SUCCESS) {
224                 HKS_FREE_BLOB(keyFromFile);
225                 continue;
226             }
227             ret = GetKeyParamSet(&keyFromFile, keyInfoList[realCnt].paramSet);
228             HKS_FREE_BLOB(keyFromFile);
229             HKS_IF_NOT_SUCC_LOGE_BREAK(ret, "get old key paramSet failed, ret = %" LOG_PUBLIC "d", ret)
230             ++realCnt;
231         }
232         *listCount = realCnt;
233         return HKS_SUCCESS;
234     } while (0);
235 
236     *listCount = realCnt;
237 
238     return ret;
239 }
240 
HksGetOldKeyInfoListForSmallToService(const struct HksProcessInfo * processInfo,struct HksKeyInfo * keyInfoList,uint32_t listMaxCnt,uint32_t * listCount)241 int32_t HksGetOldKeyInfoListForSmallToService(const struct HksProcessInfo *processInfo, struct HksKeyInfo *keyInfoList,
242     uint32_t listMaxCnt, uint32_t *listCount)
243 {
244     int32_t ret;
245 
246     // remain buffer count for old key info
247     uint32_t listCountOld = listMaxCnt - *listCount;
248     do {
249         struct HksProcessInfo rootProcessInfo;
250         ret = HksConstructRootProcessInfo(&rootProcessInfo);
251         HKS_IF_NOT_SUCC_BREAK(ret, "construct root process info failed!")
252         ret = HksGetkeyInfoListByProcessName(&rootProcessInfo, NULL, keyInfoList + *listCount, &listCountOld);
253         HKS_IF_NOT_SUCC_LOGE_BREAK(ret, "get key info list in old path failed!")
254 
255         *listCount = *listCount + listCountOld;
256     } while (0);
257     return ret;
258 }
259 #endif
260