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
28using namespace std;
29using namespace OHOS::Security::AccessToken;
30
31static 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
72static 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
118static 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
169static 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
195int32_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
220int32_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