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 
20 #define HAP_APPID_SPLIT_CHA    '_'
21 #define BASE_NUM_TWO   2
22 #define BASE_NUM_THREE  3
23 #define BASE_NUM_FOUR  4
24 #define MAX_BASE64_PADDING_LEN  2
25 #define MAX_PUBKEY_LEN  512
26 #define UNCOMPRESSED_PUBKEY_PREFIX 0x04
27 
28 using namespace std;
29 using namespace OHOS::Security::AccessToken;
30 
Base64Decode(string & encodedStr,unsigned char * decodedStr,uint32_t * decodedLen)31 static int32_t Base64Decode(string& encodedStr, unsigned char *decodedStr, uint32_t *decodedLen)
32 {
33     size_t encodedLen = encodedStr.length();
34     if (encodedLen == 0 || encodedLen % BASE_NUM_FOUR != 0) {
35         tloge("invaild based64 string, size %zu\n", encodedLen);
36         return -1;
37     }
38     if (*decodedLen < ((encodedLen / BASE_NUM_FOUR) * BASE_NUM_THREE)) {
39         tloge("decode string len too short, %zu, %u\n", encodedLen, (unsigned int)*decodedLen);
40         return -1;
41     }
42 
43     int32_t ret = EVP_DecodeBlock(decodedStr, (const unsigned char*)encodedStr.c_str(), (int)encodedLen);
44     if (ret < 0) {
45         tloge("EVP DecodeBlock failed, ret %d\n", ret);
46         return -1;
47     }
48 
49     uint32_t padLen = 0;
50     for (uint32_t i = 1; i <= BASE_NUM_FOUR; i++) {
51         if (encodedStr.at(encodedLen - i) == '=') {
52             padLen++;
53         } else {
54             break;
55         }
56     }
57 
58     if (padLen > MAX_BASE64_PADDING_LEN) {
59         tloge("invaild base64 padding len, %u\n", padLen);
60         return -1;
61     }
62 
63     if (ret == 0 || ret <= padLen) {
64         tloge("base64 decoded failed, decoded len %u, pad len %u\n", ret, padLen);
65         return -1;
66     }
67 
68     *decodedLen = ret - padLen;
69     return 0;
70 }
71 
FillEccHapCaInfo(string & packageName,const char * pubKey,uint32_t pubKeyLen,CaAuthInfo * caInfo)72 static int32_t FillEccHapCaInfo(string& packageName, const char *pubKey, uint32_t pubKeyLen, CaAuthInfo *caInfo)
73 {
74     /* certs format: packageNameLen || packageName || pubKeyLen || pubKey (xLen || x || yLen || y) */
75     uint64_t hapInfoSize = sizeof(uint32_t) + packageName.length() +
76         sizeof(uint32_t) + sizeof(uint32_t) * BASE_NUM_TWO + pubKeyLen;
77     if (hapInfoSize > sizeof(caInfo->certs)) {
78         tloge("buf too short, %u, %zu, %u\n", (unsigned int)sizeof(caInfo->certs), packageName.length(), pubKeyLen);
79         return -1;
80     }
81 
82     /* packageNameLen || packageName */
83     uint32_t offset = 0;
84     *((uint32_t *)(caInfo->certs + offset)) = packageName.length();
85     offset += sizeof(uint32_t);
86     packageName.copy((char *)caInfo->certs + offset, packageName.length(), 0);
87     offset += packageName.length();
88 
89     /* pubKey: pubKeyLen */
90     *((uint32_t *)(caInfo->certs + offset)) = pubKeyLen + sizeof(uint32_t) * BASE_NUM_TWO;
91     offset += sizeof(uint32_t);
92 
93     /* pubKey: ecc.xLen */
94     *((uint32_t *)(caInfo->certs + offset)) = pubKeyLen / BASE_NUM_TWO;
95     offset += sizeof(uint32_t);
96     /* pubKey: ecc.x */
97     if (memcpy_s(caInfo->certs + offset, sizeof(caInfo->certs) - offset,
98         pubKey, pubKeyLen / BASE_NUM_TWO) != EOK) {
99         tloge("copy ecc pubkey x point failed\n");
100         return -1;
101     }
102     offset += pubKeyLen / BASE_NUM_TWO;
103 
104     /* pubKey: ecc.yLen */
105     *((uint32_t *)(caInfo->certs + offset)) = pubKeyLen / BASE_NUM_TWO;
106     offset += sizeof(uint32_t);
107     /* pubKey: ecc.y */
108     if (memcpy_s(caInfo->certs + offset, sizeof(caInfo->certs) - offset,
109         pubKey + pubKeyLen / BASE_NUM_TWO, pubKeyLen / BASE_NUM_TWO) != EOK) {
110         tloge("copy ecc pubkey y point failed\n");
111         return -1;
112     }
113     offset += pubKeyLen / BASE_NUM_TWO;
114 
115     return 0;
116 }
117 
ConstructHapCaInfoFromToken(uint32_t tokenID,CaAuthInfo * caInfo)118 static int32_t ConstructHapCaInfoFromToken(uint32_t tokenID, CaAuthInfo *caInfo)
119 {
120     HapTokenInfo hapTokenInfo;
121     int32_t ret = AccessTokenKit::GetHapTokenInfo(tokenID, hapTokenInfo);
122     if (ret != 0) {
123         tloge("get hap token info failed, ret %d\n", ret);
124         return ret;
125     }
126 
127     size_t appIDLen = hapTokenInfo.appID.length();
128     if (appIDLen == 0 || appIDLen > sizeof(caInfo->certs)) {
129         tloge("hap appid invaild, len %zu\n", appIDLen);
130         return -1;
131     }
132 
133     size_t posSplit = hapTokenInfo.appID.find(HAP_APPID_SPLIT_CHA);
134     if (posSplit == string::npos) {
135         tloge("hap appid format is invaild\n");
136         return -1;
137     }
138     string packageName = hapTokenInfo.appID.substr(0, posSplit);
139     string pubkeyBase64 = hapTokenInfo.appID.substr(posSplit + 1, appIDLen - posSplit - 1);
140 
141     char decodedPubkey[MAX_PUBKEY_LEN] = { 0 };
142     uint32_t decodedPubkeyLen = sizeof(decodedPubkey);
143     ret = Base64Decode(pubkeyBase64, (unsigned char *)decodedPubkey, &decodedPubkeyLen);
144     if (ret != 0) {
145         tloge("based64 pubkey decoded failed, ret %d\n", ret);
146         return ret;
147     }
148     uint8_t unCompressedPubkeyPrefix = UNCOMPRESSED_PUBKEY_PREFIX;
149     if (decodedPubkeyLen < sizeof(unCompressedPubkeyPrefix) || decodedPubkey[0] != unCompressedPubkeyPrefix) {
150         tloge("invaild decoded pubkey, %u\n", decodedPubkeyLen);
151         return -1;
152     }
153     decodedPubkeyLen = decodedPubkeyLen - sizeof(unCompressedPubkeyPrefix);
154 
155     if (decodedPubkeyLen == 0 || decodedPubkeyLen % BASE_NUM_TWO != 0) {
156         tloge("invaild pub key, %u\n", decodedPubkeyLen);
157         return -1;
158     }
159 
160     ret = FillEccHapCaInfo(packageName, decodedPubkey + sizeof(unCompressedPubkeyPrefix), decodedPubkeyLen, caInfo);
161     if (ret != 0) {
162         tloge("fill ecc hap cainfo failed, ret %d\n", ret);
163         return ret;
164     }
165     caInfo->type = APP_CA;
166     return 0;
167 }
168 
ConstructNativeCaInfoFromToken(uint32_t tokenID,CaAuthInfo * caInfo)169 static int32_t ConstructNativeCaInfoFromToken(uint32_t tokenID, CaAuthInfo *caInfo)
170 {
171     NativeTokenInfo nativeTokenInfo;
172     int32_t ret = AccessTokenKit::GetNativeTokenInfo(tokenID, nativeTokenInfo);
173     if (ret == 0) {
174         uint32_t processNameLen = nativeTokenInfo.processName.length();
175         if (processNameLen == 0 || processNameLen > sizeof(caInfo->certs)) {
176             tloge("native ca process name too long, len %u\n", processNameLen);
177             return -1;
178         }
179 
180         nativeTokenInfo.processName.copy((char *)caInfo->certs, processNameLen, 0);
181     } else {
182         tlogd("get native token info from atm failed, ret %d\n", ret);
183         int32_t rc = TeeGetPkgName(caInfo->pid, (char *)caInfo->certs, MAX_PATH_LENGTH);
184         if (rc != 0) {
185             tloge("get native ca info failed, rc %d\n", rc);
186             return -1;
187         }
188     }
189 
190     caInfo->type = SA_CA;
191 
192     return 0;
193 }
194 
ConstructCaAuthInfo(uint32_t tokenID,CaAuthInfo * caInfo)195 int32_t ConstructCaAuthInfo(uint32_t tokenID, CaAuthInfo *caInfo)
196 {
197     if (caInfo == nullptr) {
198         tloge("bad params, ca info is null\n");
199         return -1;
200     }
201 
202     ATokenTypeEnum tokenType = AccessTokenKit::GetTokenTypeFlag(tokenID);
203     switch (tokenType) {
204         case TOKEN_HAP:     /* for hap ca */
205             tlogd("hap ca type, tokenID %u\n", tokenID);
206             return ConstructHapCaInfoFromToken(tokenID, caInfo);
207         case TOKEN_NATIVE:  /* for native ca */
208             tlogd("native ca type, tokenID %u\n", tokenID);
209             return ConstructNativeCaInfoFromToken(tokenID, caInfo);
210         case TOKEN_SHELL:   /* for native ca created by hdc */
211             tlogd("shell ca type, tokenID %u\n", tokenID);
212             caInfo->type = SYSTEM_CA;
213             return 0;       /* cainfo: cmdline + uid */
214         default:
215             tloge("invaild token type %d\n", tokenType);
216             return -1;
217     }
218 }
219 
TEEGetNativeSACaInfo(const CaAuthInfo * caInfo,uint8_t * buf,uint32_t bufLen)220 int32_t TEEGetNativeSACaInfo(const CaAuthInfo *caInfo, uint8_t *buf, uint32_t bufLen)
221 {
222     if (caInfo == nullptr || buf == nullptr || bufLen == 0) {
223         tloge("bad params\n");
224         return -1;
225     }
226 
227     /* buf format: processNameLen || processName || uidLen || uid */
228     uint32_t processNameLen = strnlen((char *)caInfo->certs, sizeof(caInfo->certs));
229     uint32_t uidLen = sizeof(caInfo->uid);
230 
231     uint64_t caInfoSize = sizeof(processNameLen) + processNameLen + sizeof(uidLen) + uidLen;
232     if ((uint64_t)bufLen < caInfoSize) {
233         tloge("buf too short, %u, %u\n", bufLen, processNameLen);
234         return -1;
235     }
236 
237     /* processNameLen */
238     uint32_t offset = 0;
239     if (memcpy_s(buf + offset, bufLen - offset, &processNameLen, sizeof(processNameLen)) != EOK) {
240         tloge("copy process name len failed\n");
241         return -1;
242     }
243     offset += sizeof(processNameLen);
244     /* processName */
245     if (memcpy_s(buf + offset, bufLen - offset, caInfo->certs, processNameLen) != EOK) {
246         tloge("copy process name failed\n");
247         return -1;
248     }
249     offset += processNameLen;
250     /* uidLen */
251     if (memcpy_s(buf + offset, bufLen - offset, &uidLen, sizeof(uidLen)) != EOK) {
252         tloge("copy uid len failed\n");
253         return -1;
254     }
255     offset += sizeof(uidLen);
256     /* uid */
257     if (memcpy_s(buf + offset, bufLen - offset, &(caInfo->uid), uidLen) != EOK) {
258         tloge("copy uid failed\n");
259         return -1;
260     }
261 
262     return 0;
263 }
264