1 /*
2 * Copyright (C) 2023 Huawei Technologies Co., Ltd.
3 * Licensed under the Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 * http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9 * PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 */
12
13 #include "tee_auth_system.h"
14 #include "tee_auth_common.h"
15 #include "tee_log.h"
16 #include "accesstoken_kit.h"
17 #include "openssl/evp.h"
18 #include <securec.h>
19 #include <cstring>
20 #include "ipc_skeleton.h"
21 #include "iservice_registry.h"
22 #include "if_system_ability_manager.h"
23 #include "system_ability_definition.h"
24 #include "bundle_mgr_mini_proxy.h"
25
26 #define HAP_APPID_SPLIT_CHA '_'
27 #define BASE_NUM_TWO 2
28 #define BASE_NUM_THREE 3
29 #define BASE_NUM_FOUR 4
30 #define MAX_BASE64_PADDING_LEN 2
31 #define MAX_PUBKEY_LEN 512
32 #define UNCOMPRESSED_PUBKEY_PREFIX 0x04
33
34 using namespace std;
35 using namespace OHOS;
36 using namespace OHOS::Security::AccessToken;
37
Base64Decode(string & encodedStr,unsigned char * decodedStr,uint32_t * decodedLen)38 static int32_t Base64Decode(string& encodedStr, unsigned char *decodedStr, uint32_t *decodedLen)
39 {
40 size_t encodedLen = encodedStr.length();
41 if (encodedLen == 0 || encodedLen % BASE_NUM_FOUR != 0) {
42 tloge("invaild based64 string, size %" PUBLIC "zu\n", encodedLen);
43 return -1;
44 }
45 if (*decodedLen < ((encodedLen / BASE_NUM_FOUR) * BASE_NUM_THREE)) {
46 tloge("decode string len too short, %" PUBLIC "zu, %" PUBLIC "u\n", encodedLen, (unsigned int)*decodedLen);
47 return -1;
48 }
49
50 int32_t ret = EVP_DecodeBlock(decodedStr, (const unsigned char*)encodedStr.c_str(), (int)encodedLen);
51 if (ret < 0) {
52 tloge("EVP DecodeBlock failed, ret %" PUBLIC "d\n", ret);
53 return -1;
54 }
55
56 uint32_t padLen = 0;
57 for (uint32_t i = 1; i <= BASE_NUM_FOUR; i++) {
58 if (encodedStr.at(encodedLen - i) == '=') {
59 padLen++;
60 } else {
61 break;
62 }
63 }
64
65 if (padLen > MAX_BASE64_PADDING_LEN) {
66 tloge("invaild base64 padding len, %" PUBLIC "u\n", padLen);
67 return -1;
68 }
69
70 if (ret == 0 || ret <= static_cast<int32_t>(padLen)) {
71 tloge("base64 decoded failed, decoded len %" PUBLIC "u, pad len %" PUBLIC "u\n", ret, padLen);
72 return -1;
73 }
74
75 *decodedLen = ret - padLen;
76 return 0;
77 }
78
FillEccHapCaInfo(string & packageName,const char * pubKey,uint32_t pubKeyLen,CaAuthInfo * caInfo)79 static int32_t FillEccHapCaInfo(string& packageName, const char *pubKey, uint32_t pubKeyLen, CaAuthInfo *caInfo)
80 {
81 /* certs format: packageNameLen || packageName || pubKeyLen || pubKey (xLen || x || yLen || y) */
82 uint64_t hapInfoSize = sizeof(uint32_t) + packageName.length() +
83 sizeof(uint32_t) + sizeof(uint32_t) * BASE_NUM_TWO + pubKeyLen;
84 if (hapInfoSize > sizeof(caInfo->certs)) {
85 tloge("buf too short, %" PUBLIC "u, %" PUBLIC "u, %" PUBLIC "u\n",
86 (unsigned int)sizeof(caInfo->certs), (unsigned int)packageName.length(), (unsigned int)pubKeyLen);
87 return -1;
88 }
89
90 /* packageNameLen || packageName */
91 uint32_t offset = 0;
92 *((uint32_t *)(caInfo->certs + offset)) = packageName.length();
93 offset += sizeof(uint32_t);
94 packageName.copy((char *)caInfo->certs + offset, packageName.length(), 0);
95 offset += packageName.length();
96
97 /* pubKey: pubKeyLen */
98 *((uint32_t *)(caInfo->certs + offset)) = pubKeyLen + sizeof(uint32_t) * BASE_NUM_TWO;
99 offset += sizeof(uint32_t);
100
101 /* pubKey: ecc.xLen */
102 *((uint32_t *)(caInfo->certs + offset)) = pubKeyLen / BASE_NUM_TWO;
103 offset += sizeof(uint32_t);
104 /* pubKey: ecc.x */
105 if (memcpy_s(caInfo->certs + offset, sizeof(caInfo->certs) - offset,
106 pubKey, pubKeyLen / BASE_NUM_TWO) != EOK) {
107 tloge("copy ecc pubkey x point failed\n");
108 return -1;
109 }
110 offset += pubKeyLen / BASE_NUM_TWO;
111
112 /* pubKey: ecc.yLen */
113 *((uint32_t *)(caInfo->certs + offset)) = pubKeyLen / BASE_NUM_TWO;
114 offset += sizeof(uint32_t);
115 /* pubKey: ecc.y */
116 if (memcpy_s(caInfo->certs + offset, sizeof(caInfo->certs) - offset,
117 pubKey + pubKeyLen / BASE_NUM_TWO, pubKeyLen / BASE_NUM_TWO) != EOK) {
118 tloge("copy ecc pubkey y point failed\n");
119 return -1;
120 }
121 offset += pubKeyLen / BASE_NUM_TWO;
122
123 return 0;
124 }
125
GetHapAppID(void)126 static std::string GetHapAppID(void)
127 {
128 sptr<ISystemAbilityManager> systemAbilityManager =
129 SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
130 if (systemAbilityManager == nullptr) {
131 tloge("GetBundleManagerProxy Failed to get system ability mgr.");
132 return "";
133 }
134 sptr<IRemoteObject> remoteObject =
135 systemAbilityManager->GetSystemAbility(OHOS::BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
136 if (remoteObject == nullptr) {
137 tloge("GetBundleManagerProxy Failed to get bundle manager service.");
138 return "";
139 }
140 sptr<AppExecFwk::IBundleMgr> bundleManager = iface_cast<AppExecFwk::IBundleMgr>(remoteObject);
141 if (bundleManager == nullptr) {
142 tloge("GetBundleManagerProxy bundleManager is nullptr");
143 return "";
144 }
145 /* userID */
146 int32_t uid = IPCSkeleton::GetCallingUid();
147 int32_t userId = uid / OHOS::AppExecFwk::Constants::BASE_USER_RANGE;
148 tlogd("uid=%" PUBLIC "d, userId=%" PUBLIC "d\n", uid, userId);
149
150 /* appID */
151 std::string bundleName;
152 bundleManager->GetNameForUid(uid, bundleName);
153 return bundleManager->GetAppIdByBundleName(bundleName, userId);
154 }
155
ConstructHapCaInfoFromToken(CaAuthInfo * caInfo)156 static int32_t ConstructHapCaInfoFromToken(CaAuthInfo *caInfo)
157 {
158 std::string appID = GetHapAppID();
159 if (appID.empty()) {
160 tloge("get app id failed\n");
161 return -1;
162 }
163 tlogd("appid=%" PUBLIC "s\n", appID.c_str());
164 size_t appIDLen = appID.length();
165 if (appIDLen == 0 || appIDLen > sizeof(caInfo->certs)) {
166 tloge("hap appid invaild, len %" PUBLIC "zu\n", appIDLen);
167 return -1;
168 }
169
170 size_t posSplit = appID.find_last_of(HAP_APPID_SPLIT_CHA);
171 if (posSplit == string::npos) {
172 tloge("hap appid format is invaild\n");
173 return -1;
174 }
175 string packageName = appID.substr(0, posSplit);
176 string pubkeyBase64 = appID.substr(posSplit + 1, appIDLen - posSplit - 1);
177
178 char decodedPubkey[MAX_PUBKEY_LEN] = { 0 };
179 uint32_t decodedPubkeyLen = sizeof(decodedPubkey);
180 int ret = Base64Decode(pubkeyBase64, (unsigned char *)decodedPubkey, &decodedPubkeyLen);
181 if (ret != 0) {
182 tloge("based64 pubkey decoded failed, ret %" PUBLIC "d\n", ret);
183 return ret;
184 }
185 uint8_t unCompressedPubkeyPrefix = UNCOMPRESSED_PUBKEY_PREFIX;
186 if (decodedPubkeyLen < sizeof(unCompressedPubkeyPrefix) || decodedPubkey[0] != unCompressedPubkeyPrefix) {
187 tloge("invaild decoded pubkey, %" PUBLIC "u\n", decodedPubkeyLen);
188 return -1;
189 }
190 decodedPubkeyLen = decodedPubkeyLen - sizeof(unCompressedPubkeyPrefix);
191
192 if (decodedPubkeyLen == 0 || decodedPubkeyLen % BASE_NUM_TWO != 0) {
193 tloge("invaild pub key, %" PUBLIC "u\n", decodedPubkeyLen);
194 return -1;
195 }
196
197 ret = FillEccHapCaInfo(packageName, decodedPubkey + sizeof(unCompressedPubkeyPrefix), decodedPubkeyLen, caInfo);
198 if (ret != 0) {
199 tloge("fill ecc hap cainfo failed, ret %" PUBLIC "d\n", ret);
200 return ret;
201 }
202 caInfo->type = APP_CA;
203 return 0;
204 }
205
206 #define RETRY_TIMES 5
ConstructNativeCaInfoFromToken(uint32_t tokenID,CaAuthInfo * caInfo,bool needRetry)207 static int32_t ConstructNativeCaInfoFromToken(uint32_t tokenID, CaAuthInfo *caInfo, bool needRetry)
208 {
209 NativeTokenInfo nativeTokenInfo;
210
211 int32_t ret;
212 int32_t retry = 0;
213 bool atmReady = true;
214
215 sptr<ISystemAbilityManager> saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
216 if (saMgr == nullptr) {
217 tloge("get system ability manager failed\n");
218 return -1;
219 }
220
221 if (saMgr->CheckSystemAbility(ACCESS_TOKEN_MANAGER_SERVICE_ID) == nullptr) {
222 tlogi("atm service is unready.\n");
223 atmReady = false;
224 }
225
226 if (!atmReady) {
227 tlogi("get native callinfo info not from atm\n");
228 int32_t rc = TeeGetPkgName(caInfo->pid, (char *)caInfo->certs, MAX_PATH_LENGTH);
229 if (rc != 0) {
230 tloge("get native ca info failed, rc %" PUBLIC "d\n", rc);
231 return -1;
232 }
233
234 caInfo->type = SA_CA;
235 return 0;
236 }
237
238 do {
239 retry++;
240 ret = AccessTokenKit::GetNativeTokenInfo(tokenID, nativeTokenInfo);
241 if (ret != 0) {
242 tlogi("get native token info from atm failed, retry times=%" PUBLIC "d\n", retry);
243 if (needRetry) {
244 sleep(1);
245 }
246 }
247 } while (ret != 0 && retry < RETRY_TIMES && needRetry);
248
249 if (ret != 0) {
250 tloge("get native token info from atm failed, retry times=%" PUBLIC "d, ret=0x%" PUBLIC "x\n", retry, ret);
251 return -1;
252 }
253 uint32_t processNameLen = nativeTokenInfo.processName.length();
254 if (processNameLen == 0 || processNameLen > sizeof(caInfo->certs)) {
255 tloge("native ca process name too long, len %" PUBLIC "u\n", processNameLen);
256 return -1;
257 }
258
259 nativeTokenInfo.processName.copy((char *)caInfo->certs, processNameLen, 0);
260 caInfo->type = SA_CA;
261 return 0;
262 }
263
ConstructCaAuthInfo(uint32_t tokenID,CaAuthInfo * caInfo)264 int32_t ConstructCaAuthInfo(uint32_t tokenID, CaAuthInfo *caInfo)
265 {
266 if (caInfo == nullptr) {
267 tloge("bad params, ca info is null\n");
268 return -1;
269 }
270
271 ATokenTypeEnum tokenType = AccessTokenKit::GetTokenTypeFlag(tokenID);
272 switch (tokenType) {
273 case TOKEN_HAP: /* for hap ca */
274 tlogd("hap ca type, tokenID %" PUBLIC "u\n", tokenID);
275 return ConstructHapCaInfoFromToken(caInfo);
276 case TOKEN_NATIVE: /* for native ca */
277 tlogd("native ca type, tokenID %" PUBLIC "u\n", tokenID);
278 return ConstructNativeCaInfoFromToken(tokenID, caInfo, false);
279 case TOKEN_SHELL: /* for native ca created by hdc */
280 tlogd("shell ca type, tokenID %" PUBLIC "u\n", tokenID);
281 caInfo->type = SYSTEM_CA;
282 return 0; /* cainfo: cmdline + uid */
283 default:
284 tloge("invaild token type %" PUBLIC "d\n", tokenType);
285 return -1;
286 }
287 }
288
ConstructSelfAuthInfo(CaAuthInfo * caInfo)289 int32_t ConstructSelfAuthInfo(CaAuthInfo *caInfo)
290 {
291 if (caInfo == nullptr) {
292 tloge("bad params, ca info is null\n");
293 return -1;
294 }
295
296 caInfo->pid = getpid();
297 caInfo->uid = getuid();
298
299 uint32_t selfTokenID = OHOS::IPCSkeleton::GetSelfTokenID();
300 tlogi("selfTokenID is %" PUBLIC "u\n", selfTokenID);
301
302 return ConstructNativeCaInfoFromToken(selfTokenID, caInfo, true);
303 }
304
TEEGetNativeSACaInfo(const CaAuthInfo * caInfo,uint8_t * buf,uint32_t bufLen)305 int32_t TEEGetNativeSACaInfo(const CaAuthInfo *caInfo, uint8_t *buf, uint32_t bufLen)
306 {
307 if (caInfo == nullptr || buf == nullptr || bufLen == 0) {
308 tloge("bad params\n");
309 return -1;
310 }
311
312 /* buf format: processNameLen || processName || uidLen || uid */
313 uint32_t processNameLen = strnlen((char *)caInfo->certs, sizeof(caInfo->certs));
314 uint32_t uidLen = sizeof(caInfo->uid);
315
316 uint64_t caInfoSize = sizeof(processNameLen) + processNameLen + sizeof(uidLen) + uidLen;
317 if ((uint64_t)bufLen < caInfoSize) {
318 tloge("buf too short, %" PUBLIC "u, %" PUBLIC "u\n", bufLen, processNameLen);
319 return -1;
320 }
321
322 /* processNameLen */
323 uint32_t offset = 0;
324 if (memcpy_s(buf + offset, bufLen - offset, &processNameLen, sizeof(processNameLen)) != EOK) {
325 tloge("copy process name len failed\n");
326 return -1;
327 }
328 offset += sizeof(processNameLen);
329 /* processName */
330 if (memcpy_s(buf + offset, bufLen - offset, caInfo->certs, processNameLen) != EOK) {
331 tloge("copy process name failed\n");
332 return -1;
333 }
334 offset += processNameLen;
335 /* uidLen */
336 if (memcpy_s(buf + offset, bufLen - offset, &uidLen, sizeof(uidLen)) != EOK) {
337 tloge("copy uid len failed\n");
338 return -1;
339 }
340 offset += sizeof(uidLen);
341 /* uid */
342 if (memcpy_s(buf + offset, bufLen - offset, &(caInfo->uid), uidLen) != EOK) {
343 tloge("copy uid failed\n");
344 return -1;
345 }
346
347 return 0;
348 }
349
GetCaName(char * name,int32_t len)350 void GetCaName(char *name, int32_t len)
351 {
352 const char *res = nullptr;
353 int clen = 0;
354 CaAuthInfo info = { { 0 } };
355
356 if (name == nullptr || len < MAX_PATH_LENGTH) {
357 return;
358 }
359 info.pid = IPCSkeleton::GetCallingPid();
360 info.uid = static_cast<unsigned int>(IPCSkeleton::GetCallingUid());
361 uint32_t tokenID = IPCSkeleton::GetCallingTokenID();
362 ATokenTypeEnum tokenType = AccessTokenKit::GetTokenTypeFlag(tokenID);
363 int ret = ConstructCaAuthInfo(tokenID, &info);
364 if (ret != 0) {
365 tloge("construct ca auth info failed %d\n", ret);
366 }
367 switch (tokenType) {
368 case TOKEN_SHELL:
369 ret = TeeGetPkgName(info.pid, name, len);
370 if (ret != 0) {
371 tloge("get ca name failed\n");
372 name[0] = '\0';
373 }
374 break;
375 case TOKEN_HAP:
376 res = strchr(reinterpret_cast<const char *>(info.certs), '_');
377 if (res != nullptr) {
378 clen = res - reinterpret_cast<const char *>(info.certs);
379 ret = memcpy_s(name, len, info.certs, clen);
380 if (ret != 0) {
381 tloge("get ca hap name failed\n");
382 name[0] = '\0';
383 }
384 } else {
385 tloge("find _ failed in certs %s\n", info.certs);
386 }
387 break;
388 case TOKEN_NATIVE:
389 clen = strnlen(reinterpret_cast<const char *>(info.certs), MAX_PATH_LENGTH - 1);
390 ret = memcpy_s(name, len, info.certs, clen);
391 if (ret != 0) {
392 tloge("get ca native name failed\n");
393 name[0] = '\0';
394 }
395 break;
396 default:
397 tloge("invalid type %d\n", static_cast<int32_t>(tokenType));
398 break;
399 }
400 }
401