1 /*
2 * Copyright (c) 2024 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 "module_update_verify.h"
17 #include "cert_verify.h"
18 #include "directory_ex.h"
19 #include "diff_patch/diff_patch_interface.h" // update diff interface
20 #include "hash_data_verifier.h"
21 #include "log/log.h"
22 #include "json_node.h"
23 #include "openssl/sha.h"
24 #include "parameters.h"
25 #include "scope_guard.h"
26 #include "utils.h"
27 #include "module_constants.h"
28 #include "module_file.h"
29 #include "module_utils.h"
30
31 namespace OHOS {
32 namespace SysInstaller {
33 using namespace Hpackage;
34 using namespace Updater;
35
36 namespace {
GetHmpType(const JsonNode & root,std::string & type)37 bool GetHmpType(const JsonNode &root, std::string &type)
38 {
39 const JsonNode &typeJson = root["type"];
40 std::optional<std::string> hmpType = typeJson.As<std::string>();
41 if (!hmpType.has_value()) {
42 LOG(ERROR) << "HmpInfo: Failed to get type val";
43 return false;
44 }
45 type = hmpType.value();
46 return true;
47 }
48
CheckApiVersion(const std::string & apiVersion)49 bool CheckApiVersion(const std::string &apiVersion)
50 {
51 if (apiVersion.empty()) {
52 LOG(INFO) << "apiVersion is empty, default is true.";
53 return true;
54 }
55 int sysApiVersion = GetDeviceApiVersion();
56 int hmpApiVersion = Utils::String2Int<int>(apiVersion, Utils::N_DEC);
57 if (hmpApiVersion <= sysApiVersion) {
58 return true;
59 }
60 LOG(ERROR) << "sysApiVersion: " << sysApiVersion << "; hmpApiVersion: " << hmpApiVersion;
61 return false;
62 }
63
CheckSaSdkVersion(const std::string & saSdkVersion)64 bool CheckSaSdkVersion(const std::string &saSdkVersion)
65 {
66 //sasdk_M.S.F.B
67 if (saSdkVersion.empty()) {
68 LOG(INFO) << "saSdkVersion is empty, default is true.";
69 return true;
70 }
71 std::vector<std::string> saSdkVersionVec {};
72 std::string sysSaSdkVersion = GetDeviceSaSdkVersion();
73 if (!ParseVersion(sysSaSdkVersion, "_", saSdkVersionVec)) {
74 LOG(ERROR) << "ParseVersion sysSaSdkVersion failed: " << sysSaSdkVersion;
75 return false;
76 }
77 std::vector<std::string> hmpVersionVec {};
78 if (!ParseVersion(saSdkVersion, "_", hmpVersionVec)) {
79 LOG(ERROR) << "ParseVersion hmpSaSdkVersion failed: " << saSdkVersion;
80 return false;
81 }
82 if (!CompareSaSdkVersion(saSdkVersionVec, hmpVersionVec)) {
83 LOG(ERROR) << "saSdkVersion compare fail, sys:" << sysSaSdkVersion << "; hmp:" << saSdkVersion;
84 return false;
85 }
86 return true;
87 }
88
GetPackInfoVer(const JsonNode & root,const std::string & key,std::string & version)89 bool GetPackInfoVer(const JsonNode &root, const std::string &key, std::string &version)
90 {
91 const JsonNode &package = root["package"];
92 std::optional<std::string> tmpVersion = package[key].As<std::string>();
93 if (!tmpVersion.has_value()) {
94 LOG(ERROR) << "count get version val";
95 return false;
96 }
97 version = tmpVersion.value();
98 LOG(INFO) << key << " " << version;
99 return true;
100 }
101
GetPackageType(const JsonNode & root,std::string & type)102 bool GetPackageType(const JsonNode &root, std::string &type)
103 {
104 const JsonNode &typeJson = root["packageType"];
105 std::optional<std::string> hmpPackageType = typeJson.As<std::string>();
106 if (!hmpPackageType.has_value()) {
107 LOG(ERROR) << "HmpInfo: Failed to get type val";
108 return false;
109 }
110 type = hmpPackageType.value();
111 return true;
112 }
113 }
114
CheckPackInfoVer(const std::string & pkgPackInfoPath)115 bool CheckPackInfoVer(const std::string &pkgPackInfoPath)
116 {
117 std::string packInfo = GetContentFromZip(pkgPackInfoPath, PACK_INFO_NAME);
118 JsonNode root(packInfo);
119 std::string type;
120 if (!GetHmpType(root, type)) {
121 return false;
122 }
123 LOG(INFO) << pkgPackInfoPath << "; type = " << type;
124 std::string apiVersion;
125 if (type == HMP_APP_TYPE && GetPackInfoVer(root, HMP_API_VERSION, apiVersion)) {
126 return CheckApiVersion(apiVersion);
127 }
128 std::string saSdkVersion;
129 if ((type == HMP_SA_TYPE || type == HMP_SA_TYPE_OLD) &&
130 GetPackInfoVer(root, HMP_SA_SDK_VERSION, saSdkVersion)) {
131 return CheckSaSdkVersion(saSdkVersion);
132 }
133 if ((type == HMP_MIX_TYPE || type == HMP_TRAIN_TYPE) &&
134 GetPackInfoVer(root, HMP_SA_SDK_VERSION, saSdkVersion) &&
135 GetPackInfoVer(root, HMP_API_VERSION, apiVersion)) {
136 return CheckApiVersion(apiVersion) && CheckSaSdkVersion(saSdkVersion);
137 }
138 return false;
139 }
140
CleanErrDir(const std::string & fpInfo)141 void CleanErrDir(const std::string &fpInfo)
142 {
143 if (fpInfo.find(UPDATE_ACTIVE_DIR) != std::string::npos ||
144 fpInfo.find(UPDATE_BACKUP_DIR) != std::string::npos) {
145 LOG(INFO) << "delete err dir :"<< fpInfo;
146 ForceRemoveDirectory(fpInfo.substr(0, fpInfo.rfind("/")));
147 }
148 }
149
IsIncrementPackage(const std::string & pkgPackInfoPath)150 bool IsIncrementPackage(const std::string &pkgPackInfoPath)
151 {
152 std::string packInfo = GetContentFromZip(pkgPackInfoPath, PACK_INFO_NAME);
153 JsonNode root(packInfo);
154 std::string packageType;
155 if (!GetPackageType(root, packageType)) {
156 LOG(INFO) << pkgPackInfoPath << " not support increment";
157 return false;
158 }
159 LOG(INFO) << pkgPackInfoPath << "; packageType = " << packageType;
160 if (packageType == HMP_INCR_PACKAGE_TYPE) {
161 return true;
162 }
163 return false;
164 }
165
ReadHashFromPackInfo(const std::string & pkgPackInfoPath,std::string & hashValue)166 bool ReadHashFromPackInfo(const std::string &pkgPackInfoPath, std::string &hashValue)
167 {
168 std::string packInfo = GetContentFromZip(pkgPackInfoPath, PACK_INFO_NAME);
169 JsonNode root(packInfo);
170 const JsonNode &imageHashJson = root["imageHash"];
171 std::optional<std::string> imageHash = imageHashJson.As<std::string>();
172 if (!imageHash.has_value()) {
173 LOG(ERROR) << "HmpInfo: Failed to get imageHash val";
174 return false;
175 }
176 hashValue = imageHash.value();
177 return true;
178 }
179
RestorePackage(const std::string & dstFile,const std::string & sourceFile)180 bool RestorePackage(const std::string &dstFile, const std::string &sourceFile)
181 {
182 LOG(INFO) << "Start restore file " << dstFile << "; source is " << sourceFile;
183 Timer timer;
184 if (dstFile.find(UPDATE_INSTALL_DIR) == std::string::npos) {
185 LOG(ERROR) << dstFile << " is not installDir, restore fail.";
186 return false;
187 }
188 std::string diffFile = ExtractFilePath(dstFile) + IMG_DIFF_FILE_NAME;
189 std::string restoreImgFile = ExtractFilePath(dstFile) + IMG_FILE_NAME;
190 if (!CheckPathExists(diffFile) || CheckPathExists(restoreImgFile)) {
191 LOG(ERROR) << diffFile << " is not exist or dest image exists, restore fail.";
192 return false;
193 }
194 if (!CheckPathExists(sourceFile)) {
195 LOG(ERROR) << sourceFile << " is not exist.";
196 return false;
197 }
198 int32_t result = Updater::ApplyPatch(diffFile, sourceFile, restoreImgFile);
199 if (result != 0) {
200 LOG(ERROR) << "Restore package failed, ret is " << result << " err:" << strerror(errno);
201 return false;
202 }
203 if (unlink(diffFile.c_str()) != 0) {
204 LOG(WARNING) << "Failed to unlink " << diffFile << " err:" << strerror(errno);
205 }
206 LOG(INFO) << "restore image succ, restore timer:" << timer;
207
208 std::string hashValue;
209 if (!ReadHashFromPackInfo(dstFile, hashValue)) {
210 LOG(ERROR) << "read hash from pack.info fail";
211 return false;
212 }
213 LOG(INFO) << "read hash, " << hashValue;
214 std::string calculateHash;
215 if (!CalculateSHA256(restoreImgFile, calculateHash)) {
216 LOG(ERROR) << "calculate restore image hash fail";
217 return false;
218 }
219 return (hashValue == calculateHash);
220 }
221
CalculateSHA256(const std::string & filePath,std::string & digest)222 bool CalculateSHA256(const std::string &filePath, std::string &digest)
223 {
224 char realPath[PATH_MAX] = {0};
225 if (realpath(filePath.c_str(), realPath) == nullptr) {
226 LOG(ERROR) << "invalid file path, " << filePath;
227 return false;
228 }
229 std::ifstream readFile(realPath, std::ios::binary);
230 if (!readFile) {
231 LOG(ERROR) << "open file fail, " << realPath;
232 return false;
233 }
234 SHA256_CTX sha256Context;
235 SHA256_Init(&sha256Context);
236 constexpr int32_t bufferSize = 4096;
237 char buffer[bufferSize] = {0};
238 while (!readFile.eof()) {
239 readFile.read(buffer, sizeof(buffer));
240 SHA256_Update(&sha256Context, buffer, readFile.gcount());
241 }
242 uint8_t digestBuffer[SHA256_DIGEST_LENGTH] = {0};
243 SHA256_Final(digestBuffer, &sha256Context);
244 digest = Utils::ConvertSha256Hex(digestBuffer, SHA256_DIGEST_LENGTH);
245 std::transform(digest.begin(), digest.end(), digest.begin(), ::toupper);
246 LOG(INFO) << "CalculateSHA256, " << digest;
247 return true;
248 }
249 }
250 }