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 "tcu_authentication.h"
14#include <unistd.h>
15#include <errno.h> /* for errno */
16#include <fcntl.h>
17#include <sys/types.h> /* for open close */
18#include <sys/ioctl.h> /* for ioctl */
19#include <sys/stat.h> /* for stat */
20#include <linux/limits.h>
21#include "securec.h"
22#include "tee_log.h"
23#include "tc_ns_client.h"
24#include "tee_client_type.h"
25
26#ifdef LOG_TAG
27#undef LOG_TAG
28#endif
29#define LOG_TAG            "tcu_authentication"
30#define HASH_FILE_MAX_SIZE (16 * 1024)
31#define ERR_SIZE           (-1)
32#define XML_HEADER         4
33#define MAX_HASHFILE_PATHLEN 256
34
35static const char *g_vendorCaHashFileList[] = {
36    "/vendor/etc/native_packages.xml",
37    "/vendor/root/res/native_packages.xml",
38};
39
40static const char *g_systemCaHashFileList[] = {
41    "/system/etc/native_packages.xml",
42};
43
44static const char **GetCaHashFileList(uint8_t *num, uint8_t hash_type)
45{
46    if (num == NULL) {
47        tloge("input parameter error\n");
48        return NULL;
49    }
50
51    if (hash_type == HASH_TYPE_SYSTEM) {
52        *num = sizeof(g_systemCaHashFileList) / sizeof(intptr_t);
53        return g_systemCaHashFileList;
54    } else {
55        *num = sizeof(g_vendorCaHashFileList) / sizeof(intptr_t);
56        return g_vendorCaHashFileList;
57    }
58}
59
60static int IsNotValidFname(const char *path)
61{
62    if (path == NULL) {
63        tloge("filename is invalid ...\n");
64        return 1;
65    }
66
67    /* filter the .. dir in the pname: */
68    if (strstr(path, "..") != NULL) {
69        tloge("filename should not include .. dir\n");
70        return 1;
71    }
72
73    return 0;
74}
75
76static int GetFileSize(const char *path, int *realSize)
77{
78    FILE *fp = NULL;
79    int ret;
80    int fileSize                = -1;
81    int xmlHeader               = 0;
82    char realPath[PATH_MAX + 1] = { 0 };
83
84    bool paramInvlid = ((path == NULL) || (IsNotValidFname(path) != 0) || (strlen(path) > PATH_MAX) ||
85                        (realpath(path, realPath) == NULL));
86    if (paramInvlid) {
87        return fileSize;
88    }
89
90    fp = fopen(realPath, "r");
91    if (fp == NULL) {
92        return fileSize;
93    }
94
95    ret = fseek(fp, 0L, SEEK_END);
96    if (ret < 0) {
97        fclose(fp);
98        fp = NULL;
99        return fileSize;
100    }
101
102    fileSize = (int)ftell(fp);
103
104    ret = fseek(fp, 0L, SEEK_SET);
105    if (ret < 0 || fileSize < XML_HEADER) {
106        fclose(fp);
107        fp = NULL;
108        return ERR_SIZE;
109    }
110    int len = (int)fread(&xmlHeader, 1, sizeof(int), fp);
111    if (len != sizeof(int) || xmlHeader < fileSize) {
112        tloge("size read is invalid\n");
113        fclose(fp);
114        fp = NULL;
115        return ERR_SIZE;
116    }
117
118    (void)fclose(fp);
119    fp = NULL;
120    *realSize = fileSize;
121    return xmlHeader;
122}
123
124static int GetFileInfo(int bufLen, uint8_t *buffer, const char *path)
125{
126    FILE *fp = NULL;
127    int fileSize;
128    char realPath[PATH_MAX + 1] = { 0 };
129
130    bool paramInvlid = ((buffer == NULL) || (path == NULL) || (IsNotValidFname(path) != 0) ||
131                        (strlen(path) > PATH_MAX) || (realpath(path, realPath) == NULL) ||
132                        (bufLen == 0));
133    if (paramInvlid) {
134        return -1;
135    }
136
137    fp = fopen(realPath, "rb");
138    if (fp == NULL) {
139        tloge("open file failed\n");
140        return -1;
141    }
142
143    fileSize = (int)fread(buffer, sizeof(char), (unsigned int)bufLen, fp);
144    if (fileSize != bufLen) {
145        tloge("read file read number:%d\n", fileSize);
146        fclose(fp);
147        fp = NULL;
148        return -1;
149    }
150
151    (void)fclose(fp);
152    fp = NULL;
153    return 0;
154}
155
156static uint8_t *InitTempBuf(int bufLen)
157{
158    errno_t ret;
159    uint8_t *buffer = NULL;
160
161    bool variablesCheck = ((bufLen <= 0) || (bufLen > HASH_FILE_MAX_SIZE));
162    if (variablesCheck) {
163        tloge("wrong buflen\n");
164        return buffer;
165    }
166
167    buffer = (uint8_t *)malloc((unsigned int)bufLen);
168    if (buffer == NULL) {
169        tloge("malloc failed!\n");
170        return buffer;
171    }
172
173    ret = memset_s(buffer, (unsigned int)bufLen, 0, (unsigned int)bufLen);
174    if (ret != EOK) {
175        tloge("memset failed!\n");
176        free(buffer);
177        buffer = NULL;
178        return buffer;
179    }
180
181    return buffer;
182}
183
184static uint8_t *ReadXmlFile(const char *xmlFile)
185{
186    int ret;
187    int bufLen;
188    uint8_t *buffer = NULL;
189    int realSize = 0;
190
191    bufLen = GetFileSize(xmlFile, &realSize);
192    buffer = InitTempBuf(bufLen);
193    if (buffer == NULL) {
194        tloge("init temp buffer failed\n");
195        return buffer;
196    }
197
198    ret = GetFileInfo(realSize, buffer, xmlFile);
199    if (ret != 0) {
200        tloge("get xml file info failed\n");
201        free(buffer);
202        buffer = NULL;
203        return buffer;
204    }
205
206    return buffer;
207}
208
209static int TeeSetNativeCaHash(const char *xmlFlie)
210{
211    int ret;
212    int fd          = -1;
213    uint8_t *buffer = NULL;
214
215    buffer = ReadXmlFile(xmlFlie);
216    if (buffer == NULL) {
217        tloge("read xml file failed\n");
218        return fd;
219    }
220
221    fd = open(TC_PRIVATE_DEV_NAME, O_RDWR);
222    if (fd < 0) {
223        tloge("Failed to open dev node: %d\n", errno);
224        free(buffer);
225        buffer = NULL;
226        return -1;
227    }
228    ret = ioctl(fd, (int)(TC_NS_CLIENT_IOCTL_SET_NATIVE_IDENTITY), buffer);
229    if (ret != 0) {
230        tloge("ioctl fail %d\n", ret);
231    }
232
233    free(buffer);
234    buffer = NULL;
235    close(fd);
236    fd = -1;
237    return ret;
238}
239
240static bool IsFileExist(const char *name)
241{
242    struct stat statbuf;
243
244    if (name == NULL) {
245        return false;
246    }
247    if (stat(name, &statbuf) != 0) {
248        if (errno == ENOENT) { /* file not exist */
249            tlogi("file not exist: %s\n", name);
250            return false;
251        }
252        return true;
253    }
254
255    return true;
256}
257
258int TcuAuthentication(uint8_t hash_type)
259{
260    uint8_t listLen;
261    const char **hashFileList = GetCaHashFileList(&listLen, hash_type);
262    if (hashFileList == NULL) {
263        tloge("get hashFileList failed\n");
264        return -1;
265    }
266    if (listLen == 0) {
267        tloge("list num is 0, please set hashfile\n");
268        return -1;
269    }
270    static int gHashXmlSetted;
271    uint8_t count = 0;
272    if (gHashXmlSetted == 0) {
273        for (uint8_t index = 0; index < listLen; index++) {
274            if (hashFileList[index] == NULL) {
275                tloge("get hashFile failed, index is %d\n", index);
276                continue;
277            }
278            if (!IsFileExist(hashFileList[index])) {
279                continue;
280            }
281
282            int setRet = TeeSetNativeCaHash(hashFileList[index]);
283            if (setRet != 0) {
284                tloge("hashfile read failed, index is %d\n", index);
285                continue;
286            }
287            count++;
288        }
289    }
290
291    if (count == listLen) {
292        gHashXmlSetted = 1;
293        return 0;
294    }
295
296    return -1;
297}