1 /*
2 * Copyright (c) 2020-2022 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 "app_provision.h"
17 #include <stdbool.h>
18 #include <string.h>
19 #include "app_common.h"
20 #include "app_verify_hal.h"
21 #include "cJSON.h"
22 #include "securec.h"
23
ProfInit(ProfileProf * pf)24 static void ProfInit(ProfileProf *pf)
25 {
26 errno_t ret = memset_s(pf, sizeof(ProfileProf), 0, sizeof(ProfileProf));
27 if (ret != EOK) {
28 LOG_ERROR("memset failed");
29 return;
30 }
31 return;
32 }
33
GetStringTag(const cJSON * root,const char * tag)34 static char *GetStringTag(const cJSON *root, const char *tag)
35 {
36 cJSON *jsonObj = cJSON_GetObjectItem(root, tag);
37 if ((jsonObj == NULL) || (jsonObj->valuestring == NULL)) {
38 LOG_PRINT_STR("failed to get %s", tag);
39 return NULL;
40 }
41 int objLen = strlen(jsonObj->valuestring);
42 if (objLen < 0) {
43 LOG_PRINT_STR("len error");
44 return NULL;
45 }
46 char *value = APPV_MALLOC(objLen + 1);
47 if (value == NULL) {
48 LOG_ERROR("malloc error: %d", objLen + 1);
49 return NULL;
50 }
51 errno_t ret = strcpy_s(value, objLen + 1, jsonObj->valuestring);
52 if (ret != EOK) {
53 APPV_FREE(value);
54 LOG_ERROR("strcpy error: %d", ret);
55 return NULL;
56 }
57 return value;
58 }
59
FreeStringAttay(char ** array,int num)60 static void FreeStringAttay(char **array, int num)
61 {
62 if (array == NULL) {
63 return;
64 }
65 for (int i = 0; i < num; i++) {
66 if (array[i] != NULL) {
67 APPV_FREE(array[i]);
68 }
69 }
70 APPV_FREE(array);
71 return;
72 }
73
GetStringArrayTag(const cJSON * root,const char * tag,int * numReturn)74 static char **GetStringArrayTag(const cJSON *root, const char *tag, int *numReturn)
75 {
76 cJSON *jsonObj = cJSON_GetObjectItem(root, tag);
77 if (jsonObj == NULL) {
78 LOG_PRINT_STR("failed to get %s", tag);
79 return NULL;
80 }
81 int num = cJSON_GetArraySize(jsonObj);
82 if (num == 0) {
83 LOG_ERROR("array num 0");
84 *numReturn = 0;
85 return NULL;
86 }
87 char **value = APPV_MALLOC(sizeof(char *) * num);
88 if (value == NULL) {
89 LOG_ERROR("value is null");
90 *numReturn = 0;
91 return NULL;
92 }
93 (void)memset_s(value, sizeof(char *) * num, 0, sizeof(char *) * num);
94
95 for (int i = 0; i < num; i++) {
96 cJSON *item = cJSON_GetArrayItem(jsonObj, i);
97 P_NULL_GOTO_WTTH_LOG(item);
98 if (item->valuestring == NULL) {
99 LOG_ERROR("valuestring is NULL");
100 return NULL;
101 }
102 int len = strlen(item->valuestring);
103 value[i] = APPV_MALLOC(len + 1);
104 P_NULL_GOTO_WTTH_LOG(value[i]);
105
106 errno_t ret = strcpy_s(value[i], len + 1, item->valuestring);
107 if (ret != EOK) {
108 LOG_ERROR("str cpy error : %d", ret);
109 FreeStringAttay(value, num);
110 return NULL;
111 }
112 }
113 *numReturn = num;
114 return value;
115 EXIT:
116 FreeStringAttay(value, num);
117 return NULL;
118 }
119
GetProfValidity(const cJSON * root,ProfValidity * profVal)120 static int GetProfValidity(const cJSON *root, ProfValidity *profVal)
121 {
122 cJSON *jsonObj = cJSON_GetObjectItem(root, "validity");
123 if (jsonObj == NULL) {
124 LOG_ERROR("failed to get validity");
125 return V_ERR;
126 }
127
128 cJSON *notBefore = cJSON_GetObjectItem(jsonObj, "not-before");
129 if (notBefore == NULL) {
130 LOG_ERROR("failed to get not-before");
131 return V_ERR;
132 }
133 profVal->notBefore = notBefore->valueint;
134
135 cJSON *notAfter = cJSON_GetObjectItem(jsonObj, "not-after");
136 if (notAfter == NULL) {
137 LOG_ERROR("failed to get not-after");
138 return V_ERR;
139 }
140 profVal->notAfter = notAfter->valueint;
141 return V_OK;
142 }
143
GetProfBundleInfo(const cJSON * root,ProfBundleInfo * profVal)144 static int GetProfBundleInfo(const cJSON *root, ProfBundleInfo *profVal)
145 {
146 cJSON *jsonObj = cJSON_GetObjectItem(root, "bundle-info");
147 if (jsonObj == NULL) {
148 LOG_ERROR("failed to get bundle-info");
149 return V_ERR;
150 }
151 /* if failed, free by caller */
152 profVal->developerId = GetStringTag(jsonObj, "developer-id");
153 P_NULL_RETURN_WTTH_LOG(profVal->developerId);
154
155 profVal->devCert = (unsigned char *)GetStringTag(jsonObj, "development-certificate");
156 if (profVal->devCert == NULL) {
157 LOG_ERROR("get development-certificat failed");
158 profVal->devCert = APPV_MALLOC(sizeof(char));
159 P_NULL_RETURN_WTTH_LOG(profVal->devCert);
160 profVal->devCert[0] = '\0';
161 }
162
163 profVal->releaseCert = (unsigned char *)GetStringTag(jsonObj, "distribution-certificate");
164 if (profVal->releaseCert == NULL) {
165 LOG_ERROR("get distribution-certificat failed");
166 profVal->releaseCert = APPV_MALLOC(sizeof(char));
167 P_NULL_RETURN_WTTH_LOG(profVal->releaseCert);
168 profVal->releaseCert[0] = '\0';
169 }
170
171 profVal->bundleName = GetStringTag(jsonObj, "bundle-name");
172 P_NULL_RETURN_WTTH_LOG(profVal->bundleName);
173
174 profVal->appFeature = GetStringTag(jsonObj, "app-feature");
175 P_NULL_RETURN_WTTH_LOG(profVal->appFeature);
176
177 return V_OK;
178 }
179
GetProfPermission(const cJSON * root,ProfPermission * profVal)180 static int GetProfPermission(const cJSON *root, ProfPermission *profVal)
181 {
182 cJSON *jsonObj = cJSON_GetObjectItem(root, "permissions");
183 if (jsonObj == NULL) {
184 LOG_ERROR("failed to get permissions");
185 return V_ERR;
186 }
187 profVal->permission = GetStringArrayTag(jsonObj, "feature-permissions", &profVal->permissionNum);
188 profVal->restricPermission = GetStringArrayTag(jsonObj, "restricted-permissions", &profVal->restricNum);
189 return V_OK;
190 }
191
GetProfDebugInfo(const cJSON * root,ProfDebugInfo * profVal)192 static int GetProfDebugInfo(const cJSON *root, ProfDebugInfo *profVal)
193 {
194 cJSON *jsonObj = cJSON_GetObjectItem(root, "debug-info");
195 if (jsonObj == NULL) {
196 LOG_INFO("failed to get debug-info");
197 return V_OK;
198 }
199 profVal->devIdType = GetStringTag(jsonObj, "device-id-type");
200 if (profVal->devIdType == NULL) {
201 LOG_INFO("failed to get device-id-type");
202 return V_OK;
203 }
204 profVal->deviceId = GetStringArrayTag(jsonObj, "device-ids", &profVal->devidNum);
205 return V_OK;
206 }
207
GetProfIssuerInfo(const cJSON * root,ProfileProf * pf)208 static int GetProfIssuerInfo(const cJSON *root, ProfileProf *pf)
209 {
210 pf->issuer = GetStringTag(root, "issuer");
211 if (pf->issuer == NULL) {
212 int len = strlen(APP_STORE);
213 pf->issuer = APPV_MALLOC(len + 1);
214 if (pf->issuer == NULL) {
215 return V_ERR;
216 }
217 errno_t ret = strcpy_s(pf->issuer, len + 1, APP_STORE);
218 if (ret != EOK) {
219 APPV_FREE(pf->issuer);
220 LOG_ERROR("str cpy error: %d", ret);
221 }
222 return ret;
223 }
224 return V_OK;
225 }
226
FreeProfBundle(ProfBundleInfo * pfval)227 static void FreeProfBundle(ProfBundleInfo *pfval)
228 {
229 FREE_IF_NOT_NULL(pfval->appFeature);
230 FREE_IF_NOT_NULL(pfval->bundleName);
231 FREE_IF_NOT_NULL(pfval->devCert);
232 FREE_IF_NOT_NULL(pfval->developerId);
233 FREE_IF_NOT_NULL(pfval->releaseCert);
234 return;
235 }
236
FreeProfPerssion(ProfPermission * pfval)237 static void FreeProfPerssion(ProfPermission *pfval)
238 {
239 FreeStringAttay(pfval->permission, pfval->permissionNum);
240 pfval->permissionNum = 0;
241 pfval->permission = NULL;
242
243 FreeStringAttay(pfval->restricPermission, pfval->restricNum);
244 pfval->restricNum = 0;
245 pfval->restricPermission = NULL;
246 return;
247 }
248
FreeProfDebuginfo(ProfDebugInfo * pfval)249 static void FreeProfDebuginfo(ProfDebugInfo *pfval)
250 {
251 FREE_IF_NOT_NULL(pfval->devIdType);
252
253 FreeStringAttay(pfval->deviceId, pfval->devidNum);
254 pfval->devidNum = 0;
255 pfval->deviceId = NULL;
256
257 return;
258 }
259
ProfFreeData(ProfileProf * pf)260 void ProfFreeData(ProfileProf *pf)
261 {
262 if (pf == NULL) {
263 return;
264 }
265 FREE_IF_NOT_NULL(pf->versionName);
266 FREE_IF_NOT_NULL(pf->uuid);
267 FREE_IF_NOT_NULL(pf->type);
268 FREE_IF_NOT_NULL(pf->appDistType);
269 FreeProfBundle(&pf->bundleInfo);
270 FreeProfPerssion(&pf->permission);
271 FreeProfDebuginfo(&pf->debugInfo);
272 FREE_IF_NOT_NULL(pf->issuer);
273 FREE_IF_NOT_NULL(pf->appid);
274 return;
275 }
276
277 /* parse profile */
ParseProfile(const char * buf,int len,ProfileProf * pf)278 int ParseProfile(const char *buf, int len, ProfileProf *pf)
279 {
280 P_NULL_RETURN_WTTH_LOG(pf);
281 P_NULL_RETURN_WTTH_LOG(buf);
282 ProfInit(pf);
283 int ret;
284 char *pfStr = strchr(buf, '{');
285 P_NULL_RETURN_WTTH_LOG(pfStr);
286
287 cJSON *root = cJSON_Parse(pfStr);
288 P_NULL_RETURN_WTTH_LOG(root);
289
290 cJSON *jsonObj = cJSON_GetObjectItem(root, "version-code");
291 P_NULL_GOTO_WTTH_LOG(jsonObj);
292 pf->versionCode = jsonObj->valueint;
293
294 pf->versionName = GetStringTag(root, "version-name");
295 P_NULL_GOTO_WTTH_LOG(pf->versionName);
296
297 pf->uuid = GetStringTag(root, "uuid");
298 P_NULL_GOTO_WTTH_LOG(pf->uuid);
299
300 pf->type = GetStringTag(root, "type");
301 P_NULL_GOTO_WTTH_LOG(pf->type);
302
303 pf->appDistType = GetStringTag(root, "app-distribution-type");
304 if (pf->appDistType == NULL) {
305 pf->appDistType = APPV_MALLOC(sizeof(char));
306 P_NULL_GOTO_WTTH_LOG(pf->appDistType);
307 pf->appDistType[0] = '\0';
308 }
309
310 ret = GetProfValidity(root, &pf->validity);
311 P_ERR_GOTO_WTTH_LOG(ret);
312
313 ret = GetProfBundleInfo(root, &pf->bundleInfo);
314 P_ERR_GOTO_WTTH_LOG(ret);
315
316 ret = GetProfPermission(root, &pf->permission);
317 P_ERR_GOTO_WTTH_LOG(ret);
318
319 ret = GetProfDebugInfo(root, &pf->debugInfo);
320 P_ERR_GOTO_WTTH_LOG(ret);
321
322 ret = GetProfIssuerInfo(root, pf);
323 P_ERR_GOTO_WTTH_LOG(ret);
324
325 LOG_INFO("parse profile json success");
326 cJSON_Delete(root);
327 return V_OK;
328
329 EXIT:
330 cJSON_Delete(root);
331 ProfFreeData(pf);
332 return V_ERR;
333 }
334
VerifyAppTypeAndDistribution(const ProfileProf * pf)335 static int VerifyAppTypeAndDistribution(const ProfileProf *pf)
336 {
337 if ((strcmp(pf->type, DEBUG_TYPE) != 0) && (strcmp(pf->type, RELEASE_TYPE) != 0)) {
338 LOG_PRINT_STR("invalid app type: %s", pf->type);
339 return V_ERR;
340 }
341 if (strcmp(pf->type, RELEASE_TYPE) == 0) {
342 if ((strcmp(pf->appDistType, "app_gallery") != 0) && (strcmp(pf->appDistType, "enterprise") != 0) &&
343 (strcmp(pf->appDistType, "os_integration") != 0)) {
344 LOG_PRINT_STR("invalid app dis type: %s", pf->appDistType);
345 return V_ERR;
346 }
347 }
348 return V_OK;
349 }
350
VerifyAppBundleInfo(const ProfileProf * pf)351 static int VerifyAppBundleInfo(const ProfileProf *pf)
352 {
353 if (strcmp(pf->type, DEBUG_TYPE) == 0) {
354 if (strlen((char *)pf->bundleInfo.devCert) == 0) {
355 LOG_ERROR("debug app, dev cert null");
356 return V_ERR;
357 }
358 } else if (strcmp(pf->type, RELEASE_TYPE) == 0) {
359 if (strlen((char *)pf->bundleInfo.releaseCert) == 0) {
360 LOG_ERROR("debug app, dev cert null");
361 return V_ERR;
362 }
363 } else {
364 LOG_PRINT_STR("invalid app type: %s", pf->type);
365 return V_ERR;
366 }
367 return V_OK;
368 }
369
VerifyUdid(const ProfileProf * pf)370 static int VerifyUdid(const ProfileProf *pf)
371 {
372 unsigned int size = UDID_VERIFY_BYTES + 1;
373 if (pf->debugInfo.devidNum > MAX_UDID_NUM) {
374 LOG_ERROR("udid num exceed maximum");
375 return V_ERR;
376 }
377 unsigned char *udid = APPV_MALLOC(size);
378 if (udid == NULL) {
379 LOG_ERROR("udid is null");
380 return V_ERR;
381 }
382 (void)memset_s(udid, size, 0, size);
383 int result = InquiryDeviceUdid(udid, size);
384 if (result != INQUIRY_UDID_OK) {
385 free(udid);
386 LOG_ERROR("get udid fail, ret: %d", result);
387 return V_ERR;
388 }
389 for (int i = 0; i < pf->debugInfo.devidNum; i++) {
390 if (strcmp((const char *)pf->debugInfo.deviceId[i], (const char *)udid) == 0) {
391 LOG_INFO("find right udid");
392 free(udid);
393 udid = NULL;
394 return V_OK;
395 }
396 }
397 LOG_ERROR("udid invalid");
398 free(udid);
399 udid = NULL;
400 return V_ERR;
401 }
402
VerifyDebugInfo(const ProfileProf * pf)403 static int VerifyDebugInfo(const ProfileProf *pf)
404 {
405 if (strcmp(pf->type, DEBUG_TYPE) != 0) {
406 LOG_INFO("not debug app, return ok");
407 return V_OK;
408 }
409 LOG_PRINT_STR("devid type: %s", pf->debugInfo.devIdType);
410 int ret;
411 if (strcmp(pf->debugInfo.devIdType, "udid") == 0) {
412 ret = VerifyUdid(pf);
413 } else {
414 LOG_ERROR("devid type invalid");
415 ret = V_ERR;
416 }
417 return ret;
418 }
419
VerifyProfileContent(const ProfileProf * pf)420 int VerifyProfileContent(const ProfileProf *pf)
421 {
422 P_NULL_RETURN_WTTH_LOG(pf);
423 int ret = VerifyAppTypeAndDistribution(pf);
424 if (ret != V_OK) {
425 LOG_PRINT_STR("invalid profile distribution type : %s", pf->appDistType);
426 return V_ERR_INVALID_DISP_TYPE;
427 }
428 ret = VerifyAppBundleInfo(pf);
429 if (ret != V_OK) {
430 LOG_ERROR("invalid profile app bundle info");
431 return V_ERR_INVALID_APP_BUNDLE;
432 }
433 /* verify debug device id */
434 ret = VerifyDebugInfo(pf);
435 if (ret != V_OK) {
436 LOG_ERROR("validate debug info");
437 return V_ERR_INVALID_DEVID;
438 }
439 return V_OK;
440 }
441