1 /*
2  * Copyright (C) 2021-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 "provision/provision_verify.h"
17 
18 #include <algorithm>
19 #include <map>
20 
21 #include "cJSON.h"
22 
23 #ifndef STANDARD_SYSTEM
24 #include "ohos_account_kits.h"
25 #else
26 #include "parameter.h"
27 #include "sysparam_errno.h"
28 #endif // STANDARD_SYSTEM
29 
30 #include "common/hap_verify_log.h"
31 #include "init/device_type_manager.h"
32 
33 
34 namespace {
35 const std::string KEY_VERSION_CODE = "version-code";
36 const std::string KEY_VERSION_NAME = "version-name";
37 const std::string KEY_UUID = "uuid";
38 const std::string KEY_TYPE = "type";
39 const std::string KEY_APP_DIST_TYPE = "app-distribution-type";
40 const std::string KEY_BUNDLE_INFO = "bundle-info";
41 const std::string KEY_DEVELOPER_ID = "developer-id";
42 const std::string KEY_DEVELOPMENT_CERTIFICATE = "development-certificate";
43 const std::string KEY_DISTRIBUTION_CERTIFICATE = "distribution-certificate";
44 const std::string KEY_BUNDLE_NAME = "bundle-name";
45 const std::string KEY_APL = "apl";
46 const std::string KEY_APP_FEATURE = "app-feature";
47 const std::string KEY_ACLS = "acls";
48 const std::string KEY_ALLOWED_ACLS = "allowed-acls";
49 const std::string KEY_PERMISSIONS = "permissions";
50 const std::string KEY_DATA_GROUP_IDS = "data-group-ids";
51 const std::string KEY_RESTRICTED_PERMISSIONS = "restricted-permissions";
52 const std::string KEY_RESTRICTED_CAPABILITIES = "restricted-capabilities";
53 const std::string KEY_DEBUG_INFO = "debug-info";
54 const std::string KEY_DEVICE_ID_TYPE = "device-id-type";
55 const std::string KEY_DEVICE_IDS = "device-ids";
56 const std::string KEY_ISSUER = "issuer";
57 const std::string KEY_APP_PRIVILEGE_CAPABILITIES = "app-privilege-capabilities";
58 const std::string KEY_APP_SERVICES_CAPABILITIES = "app-services-capabilities";
59 const std::string VALUE_TYPE_RELEASE = "release";
60 const std::string VALUE_DIST_TYPE_APP_GALLERY = "app_gallery";
61 const std::string VALUE_DIST_TYPE_ENTERPRISE = "enterprise";
62 const std::string VALUE_DIST_TYPE_ENTERPRISE_NORMAL = "enterprise_normal";
63 const std::string VALUE_DIST_TYPE_ENTERPRISE_MDM = "enterprise_mdm";
64 const std::string VALUR_DIST_TYPE_INTERNALTESTING = "internaltesting";
65 const std::string VALUE_DIST_TYPE_OS_INTEGRATION = "os_integration";
66 const std::string VALUE_DIST_TYPE_CROWDTESTING = "crowdtesting";
67 const std::string VALUE_DEVICE_ID_TYPE_UDID = "udid";
68 const std::string VALUE_VALIDITY = "validity";
69 const std::string VALUE_NOT_BEFORE = "not-before";
70 const std::string VALUE_NOT_AFTER = "not-after";
71 
72 // reserved field
73 const std::string KEY_BASEAPP_INFO = "baseapp-info";
74 const std::string KEY_PACKAGE_NAME = "package-name";
75 const std::string KEY_PACKAGE_CERT = "package-cert";
76 const std::string KEY_APP_IDENTIFIER = "app-identifier";
77 
78 const std::string GENERIC_BUNDLE_NAME = ".*";
79 
80 const int32_t VERSION_CODE_TWO = 2;
81 
GetStringIfExist(const cJSON * obj,const std::string & key,std::string & out)82 void GetStringIfExist(const cJSON* obj, const std::string& key, std::string& out)
83 {
84     if (obj == nullptr || !cJSON_IsObject(obj)) {
85         return;
86     }
87     cJSON* jsonValue = cJSON_GetObjectItemCaseSensitive(obj, key.c_str());
88     if (jsonValue != nullptr && cJSON_IsString(jsonValue)) {
89         out = jsonValue->valuestring;
90     }
91 }
92 
GetInt32IfExist(const cJSON * obj,const std::string & key,int32_t & out)93 void GetInt32IfExist(const cJSON* obj, const std::string& key, int32_t& out)
94 {
95     if (obj == nullptr || !cJSON_IsObject(obj)) {
96         return;
97     }
98     cJSON* jsonValue = cJSON_GetObjectItemCaseSensitive(obj, key.c_str());
99     if (jsonValue != nullptr && cJSON_IsNumber(jsonValue)) {
100         out = jsonValue->valueint;
101     }
102 }
103 
GetInt64IfExist(const cJSON * obj,const std::string & key,int64_t & out)104 void GetInt64IfExist(const cJSON* obj, const std::string& key, int64_t& out)
105 {
106     if (obj == nullptr || !cJSON_IsObject(obj)) {
107         return;
108     }
109     cJSON* jsonValue = cJSON_GetObjectItemCaseSensitive(obj, key.c_str());
110     if (jsonValue != nullptr && cJSON_IsNumber(jsonValue)) {
111         out = cJSON_GetNumberValue(jsonValue);
112     }
113 }
114 
GetStringArrayIfExist(const cJSON * obj,const std::string & key,std::vector<std::string> & out)115 void GetStringArrayIfExist(const cJSON* obj, const std::string& key, std::vector<std::string>& out)
116 {
117     if (obj == nullptr || !cJSON_IsObject(obj)) {
118         return;
119     }
120     cJSON* jsonArray = cJSON_GetObjectItemCaseSensitive(obj, key.c_str());
121     if (jsonArray == nullptr || !cJSON_IsArray(jsonArray)) {
122         return;
123     }
124     cJSON* item = nullptr;
125     cJSON_ArrayForEach(item, jsonArray) {
126         if (item != nullptr && cJSON_IsString(item)) {
127             out.emplace_back(item->valuestring);
128         }
129     }
130 }
131 
GetJsonObjectIfExist(const cJSON * obj,const std::string & key,cJSON ** out)132 void GetJsonObjectIfExist(const cJSON* obj, const std::string& key, cJSON** out)
133 {
134     if (obj == nullptr || !cJSON_IsObject(obj)) {
135         return;
136     }
137     *out = cJSON_GetObjectItemCaseSensitive(obj, key.c_str());
138 }
139 } // namespace
140 
141 namespace OHOS {
142 namespace Security {
143 namespace Verify {
144 const std::map<std::string, int32_t> distTypeMap = {
145     {VALUE_DIST_TYPE_APP_GALLERY, AppDistType::APP_GALLERY},
146     {VALUE_DIST_TYPE_ENTERPRISE, AppDistType::ENTERPRISE},
147     {VALUE_DIST_TYPE_ENTERPRISE_NORMAL, AppDistType::ENTERPRISE_NORMAL},
148     {VALUE_DIST_TYPE_ENTERPRISE_MDM, AppDistType::ENTERPRISE_MDM},
149     {VALUE_DIST_TYPE_OS_INTEGRATION, AppDistType::OS_INTEGRATION},
150     {VALUE_DIST_TYPE_CROWDTESTING, AppDistType::CROWDTESTING},
151     {VALUR_DIST_TYPE_INTERNALTESTING, AppDistType::INTERNALTESTING}
152 };
153 
154 static bool g_isRdDevice = false;
155 
ParseType(const cJSON * obj,ProvisionInfo & out)156 void ParseType(const cJSON* obj, ProvisionInfo& out)
157 {
158     std::string type;
159     GetStringIfExist(obj, KEY_TYPE, type);
160     /* If not release, then it's debug */
161     out.type = (type == VALUE_TYPE_RELEASE) ? ProvisionType::RELEASE : ProvisionType::DEBUG;
162 }
163 
ParseAppDistType(const cJSON * obj,ProvisionInfo & out)164 void ParseAppDistType(const cJSON* obj, ProvisionInfo& out)
165 {
166     std::string distType;
167     GetStringIfExist(obj, KEY_APP_DIST_TYPE, distType);
168     if (distTypeMap.find(distType) != distTypeMap.end()) {
169         out.distributionType = static_cast<AppDistType>(distTypeMap.at(distType));
170         return;
171     }
172     out.distributionType = AppDistType::NONE_TYPE;
173 }
174 
ParseBundleInfo(const cJSON * obj,ProvisionInfo & out)175 void ParseBundleInfo(const cJSON* obj, ProvisionInfo& out)
176 {
177     cJSON* bundleInfo = nullptr;
178     GetJsonObjectIfExist(obj, KEY_BUNDLE_INFO, &bundleInfo);
179     GetStringIfExist(bundleInfo, KEY_DEVELOPER_ID, out.bundleInfo.developerId);
180     GetStringIfExist(bundleInfo, KEY_DEVELOPMENT_CERTIFICATE, out.bundleInfo.developmentCertificate);
181     GetStringIfExist(bundleInfo, KEY_DISTRIBUTION_CERTIFICATE, out.bundleInfo.distributionCertificate);
182     GetStringIfExist(bundleInfo, KEY_BUNDLE_NAME, out.bundleInfo.bundleName);
183     GetStringIfExist(bundleInfo, KEY_APL, out.bundleInfo.apl);
184     GetStringIfExist(bundleInfo, KEY_APP_FEATURE, out.bundleInfo.appFeature);
185     GetStringIfExist(bundleInfo, KEY_APP_IDENTIFIER, out.bundleInfo.appIdentifier);
186     GetStringArrayIfExist(bundleInfo, KEY_DATA_GROUP_IDS, out.bundleInfo.dataGroupIds);
187 }
188 
ParseAcls(const cJSON * obj,ProvisionInfo & out)189 void ParseAcls(const cJSON* obj, ProvisionInfo& out)
190 {
191     cJSON* acls = nullptr;
192     GetJsonObjectIfExist(obj, KEY_ACLS, &acls);
193     GetStringArrayIfExist(acls, KEY_ALLOWED_ACLS, out.acls.allowedAcls);
194 }
195 
ParsePermissions(const cJSON * obj,ProvisionInfo & out)196 void ParsePermissions(const cJSON* obj, ProvisionInfo& out)
197 {
198     cJSON* permissions = nullptr;
199     GetJsonObjectIfExist(obj, KEY_PERMISSIONS, &permissions);
200     GetStringArrayIfExist(permissions, KEY_RESTRICTED_PERMISSIONS, out.permissions.restrictedPermissions);
201     GetStringArrayIfExist(permissions, KEY_RESTRICTED_CAPABILITIES, out.permissions.restrictedCapabilities);
202 }
203 
ParseDebugInfo(const cJSON * obj,ProvisionInfo & out)204 void ParseDebugInfo(const cJSON* obj, ProvisionInfo& out)
205 {
206     cJSON* debugInfo = nullptr;
207     GetJsonObjectIfExist(obj, KEY_DEBUG_INFO, &debugInfo);
208     GetStringIfExist(debugInfo, KEY_DEVICE_ID_TYPE, out.debugInfo.deviceIdType);
209     GetStringArrayIfExist(debugInfo, KEY_DEVICE_IDS, out.debugInfo.deviceIds);
210 }
211 
ParseValidity(const cJSON * obj,Validity & out)212 void ParseValidity(const cJSON* obj, Validity& out)
213 {
214     cJSON* validity = nullptr;
215     GetJsonObjectIfExist(obj, VALUE_VALIDITY, &validity);
216     GetInt64IfExist(validity, VALUE_NOT_BEFORE, out.notBefore);
217     GetInt64IfExist(validity, VALUE_NOT_AFTER, out.notAfter);
218 }
219 
ParseMetadata(const cJSON * obj,ProvisionInfo & out)220 void ParseMetadata(const cJSON* obj, ProvisionInfo& out)
221 {
222     cJSON* baseAppInfo = nullptr;
223     GetJsonObjectIfExist(obj, KEY_BASEAPP_INFO, &baseAppInfo);
224     Metadata metadata;
225     metadata.name = KEY_PACKAGE_NAME;
226     GetStringIfExist(baseAppInfo, KEY_PACKAGE_NAME, metadata.value);
227     out.metadatas.emplace_back(metadata);
228     metadata.name = KEY_PACKAGE_CERT;
229     GetStringIfExist(baseAppInfo, KEY_PACKAGE_CERT, metadata.value);
230     out.metadatas.emplace_back(metadata);
231 }
232 
from_json(const cJSON * obj,ProvisionInfo & out)233 void from_json(const cJSON* obj, ProvisionInfo& out)
234 {
235     if (obj == nullptr || !cJSON_IsObject(obj)) {
236         return;
237     }
238     GetInt32IfExist(obj, KEY_VERSION_CODE, out.versionCode);
239     GetStringIfExist(obj, KEY_VERSION_NAME, out.versionName);
240     GetStringIfExist(obj, KEY_UUID, out.uuid);
241     ParseType(obj, out);
242     ParseAppDistType(obj, out);
243     ParseBundleInfo(obj, out);
244     ParseAcls(obj, out);
245     ParsePermissions(obj, out);
246     ParseDebugInfo(obj, out);
247     GetStringIfExist(obj, KEY_ISSUER, out.issuer);
248     GetStringArrayIfExist(obj, KEY_APP_PRIVILEGE_CAPABILITIES, out.appPrivilegeCapabilities);
249     ParseValidity(obj, out.validity);
250     ParseMetadata(obj, out);
251 
252     cJSON* jsonValue = cJSON_GetObjectItemCaseSensitive(obj, KEY_APP_SERVICES_CAPABILITIES.c_str());
253     if (jsonValue != nullptr) {
254         char* dumpString = cJSON_Print(jsonValue);
255         if (dumpString != nullptr) {
256             out.appServiceCapabilities = dumpString;
257         }
258         cJSON_free(dumpString);
259     }
260 }
261 
262 #define RETURN_IF_STRING_IS_EMPTY(str, msg) \
263     if (str.empty()) {                      \
264         HAPVERIFY_LOG_ERROR(msg);    \
265         return PROVISION_INVALID;           \
266     }
267 
268 #define RETURN_IF_INT_IS_NON_POSITIVE(num, msg) \
269     if (num <= 0) {                             \
270         HAPVERIFY_LOG_ERROR(msg);        \
271         return PROVISION_INVALID;               \
272     }
273 
ParseProvision(const std::string & appProvision,ProvisionInfo & info)274 AppProvisionVerifyResult ParseProvision(const std::string& appProvision, ProvisionInfo& info)
275 {
276     cJSON* obj = cJSON_Parse(appProvision.c_str());
277     if (obj == nullptr || !cJSON_IsObject(obj)) {
278         cJSON_Delete(obj);
279         return PROVISION_INVALID;
280     }
281     from_json(obj, info);
282     cJSON_Delete(obj);
283 
284     RETURN_IF_INT_IS_NON_POSITIVE(info.versionCode, "Tag version code is empty.")
285     RETURN_IF_STRING_IS_EMPTY(info.versionName, "Tag version name is empty.")
286     RETURN_IF_STRING_IS_EMPTY(info.uuid, "Tag uuid is empty.")
287     RETURN_IF_STRING_IS_EMPTY(info.bundleInfo.developerId, "Tag developer-id is empty.")
288     if (info.type == ProvisionType::DEBUG) {
289         RETURN_IF_STRING_IS_EMPTY(info.bundleInfo.developmentCertificate, "Tag development-certificate is empty.")
290     } else if (info.type == ProvisionType::RELEASE) {
291         RETURN_IF_INT_IS_NON_POSITIVE(info.distributionType, "Tag app-distribution-type is empty.")
292         RETURN_IF_STRING_IS_EMPTY(info.bundleInfo.distributionCertificate, "Tag distribution-certificate is empty.")
293     }
294     RETURN_IF_STRING_IS_EMPTY(info.bundleInfo.bundleName, "Tag bundle-name is empty.")
295     if (info.bundleInfo.bundleName == GENERIC_BUNDLE_NAME) {
296         HAPVERIFY_LOG_DEBUG("generic package name: %{public}s, is used.", GENERIC_BUNDLE_NAME.c_str());
297     }
298     if (info.versionCode >= VERSION_CODE_TWO) {
299         RETURN_IF_STRING_IS_EMPTY(info.bundleInfo.apl, "Tag apl is empty.");
300     }
301     RETURN_IF_STRING_IS_EMPTY(info.bundleInfo.appFeature, "Tag app-feature is empty.")
302 
303     return PROVISION_OK;
304 }
305 
CheckDeviceID(const std::vector<std::string> & deviceIds,const std::string & deviceId)306 bool CheckDeviceID(const std::vector<std::string>& deviceIds, const std::string& deviceId)
307 {
308     auto iter = find(deviceIds.begin(), deviceIds.end(), deviceId);
309     if (iter == deviceIds.end()) {
310         DeviceTypeManager& deviceTypeManager = DeviceTypeManager::GetInstance();
311         if (!deviceTypeManager.GetDeviceTypeInfo()) {
312             HAPVERIFY_LOG_ERROR("current device is not authorized");
313             return false;
314         }
315         HAPVERIFY_LOG_INFO("current device is a debug device");
316     }
317     return true;
318 }
319 
CheckDeviceID(ProvisionInfo & info)320 AppProvisionVerifyResult CheckDeviceID(ProvisionInfo& info)
321 {
322     // Checking device ids
323     if (info.debugInfo.deviceIds.empty()) {
324         HAPVERIFY_LOG_ERROR("device-id list is empty.");
325         return PROVISION_DEVICE_UNAUTHORIZED;
326     }
327 
328     HAPVERIFY_LOG_DEBUG("number of device ids in list: %{public}u",
329         static_cast<uint32_t>(info.debugInfo.deviceIds.size()));
330 
331     if (info.debugInfo.deviceIdType != VALUE_DEVICE_ID_TYPE_UDID) {
332         HAPVERIFY_LOG_ERROR("type of device ID is not supported.");
333         return PROVISION_UNSUPPORTED_DEVICE_TYPE;
334     }
335 
336     std::string deviceId;
337 #ifndef STANDARD_SYSTEM
338     int32_t ret = OHOS::AccountSA::OhosAccountKits::GetInstance().GetUdid(deviceId);
339     if (ret != 0) {
340         HAPVERIFY_LOG_ERROR("obtaining current device id failed (%{public}d).", ret);
341         return PROVISION_DEVICE_UNAUTHORIZED;
342     }
343 #else
344     char udid[DEV_UUID_LEN] = {0};
345     int32_t ret = GetDevUdid(udid, sizeof(udid));
346     if (ret != EC_SUCCESS) {
347         HAPVERIFY_LOG_ERROR("obtaining current device id failed (%{public}d).", static_cast<int>(ret));
348         return PROVISION_DEVICE_UNAUTHORIZED;
349     }
350     deviceId = std::string(udid, sizeof(udid) - 1);
351 #endif // STANDARD_SYSTEM
352     if (deviceId.empty()) {
353         HAPVERIFY_LOG_ERROR("device-id of current device is empty.");
354         return PROVISION_DEVICE_UNAUTHORIZED;
355     }
356 
357     if (!CheckDeviceID(info.debugInfo.deviceIds, deviceId)) {
358         return PROVISION_DEVICE_UNAUTHORIZED;
359     }
360     return PROVISION_OK;
361 }
362 
SetRdDevice(bool isRdDevice)363 void SetRdDevice(bool isRdDevice)
364 {
365     g_isRdDevice = isRdDevice;
366 }
367 
ParseAndVerify(const std::string & appProvision,ProvisionInfo & info)368 AppProvisionVerifyResult ParseAndVerify(const std::string& appProvision, ProvisionInfo& info)
369 {
370     HAPVERIFY_LOG_DEBUG("Enter HarmonyAppProvision Verify");
371     AppProvisionVerifyResult ret = ParseProvision(appProvision, info);
372     if (ret != PROVISION_OK) {
373         return ret;
374     }
375 #ifndef X86_EMULATOR_MODE
376     HAPVERIFY_LOG_DEBUG("rd device status is %{public}d", g_isRdDevice);
377     if ((info.type == ProvisionType::DEBUG && !g_isRdDevice)
378         || info.distributionType == Security::Verify::AppDistType::INTERNALTESTING) {
379         ret = CheckDeviceID(info);
380         if (ret != PROVISION_OK) {
381             return ret;
382         }
383     }
384 #endif
385     HAPVERIFY_LOG_DEBUG("Leave HarmonyAppProvision Verify");
386     return PROVISION_OK;
387 }
388 
ParseProfile(const std::string & appProvision,ProvisionInfo & info)389 AppProvisionVerifyResult ParseProfile(const std::string& appProvision, ProvisionInfo& info)
390 {
391     cJSON* jsonObj = cJSON_Parse(appProvision.c_str());
392     if (jsonObj == nullptr || !cJSON_IsObject(jsonObj)) {
393         cJSON_Delete(jsonObj);
394         return PROVISION_INVALID;
395     }
396     from_json(jsonObj, info);
397     cJSON_Delete(jsonObj);
398     return PROVISION_OK;
399 }
400 } // namespace Verify
401 } // namespace Security
402 } // namespace OHOS
403