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