1 /*
2  * Copyright (c) 2021 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 #include "package/package.h"
16 #include <cstdio>
17 #include <cstdlib>
18 #include <iostream>
19 #include <memory>
20 #include "log/log.h"
21 #include "package/pkg_manager.h"
22 #include "securec.h"
23 
24 using namespace Updater;
25 using namespace Hpackage;
26 constexpr uint32_t VERIFY_FINSH_PERCENT = 100;
27 constexpr uint32_t MAX_ENTRY_COUNT = 4096;
28 
29 namespace {
GetUpgradePkgInfo(UpgradePkgInfo *upgradePackageInfo, std::vector<std::pair<std::string, ComponentInfo>> &files, const UpgradePkgInfoExt *pkgInfoExt, std::vector<ComponentInfoExt> &compInfo)30 int32_t GetUpgradePkgInfo(UpgradePkgInfo *upgradePackageInfo,
31     std::vector<std::pair<std::string, ComponentInfo>> &files,
32     const UpgradePkgInfoExt *pkgInfoExt,
33     std::vector<ComponentInfoExt> &compInfo)
34 {
35     if (pkgInfoExt->entryCount > MAX_ENTRY_COUNT) {
36         LOG(ERROR) << "entry count oversized " << pkgInfoExt->entryCount << ", " << MAX_ENTRY_COUNT;
37         return PKG_INVALID_PARAM;
38     }
39 
40     upgradePackageInfo->updateFileVersion = pkgInfoExt->updateFileVersion;
41     if (pkgInfoExt->softwareVersion != nullptr) {
42         upgradePackageInfo->softwareVersion = pkgInfoExt->softwareVersion;
43     }
44     if (pkgInfoExt->productUpdateId != nullptr) {
45         upgradePackageInfo->productUpdateId = pkgInfoExt->productUpdateId;
46     }
47     if (pkgInfoExt->descriptPackageId != nullptr) {
48         upgradePackageInfo->descriptPackageId = pkgInfoExt->descriptPackageId;
49     }
50     if (pkgInfoExt->time != nullptr) {
51         upgradePackageInfo->time = pkgInfoExt->time;
52     }
53     if (pkgInfoExt->date != nullptr) {
54         upgradePackageInfo->date = pkgInfoExt->date;
55     }
56     upgradePackageInfo->pkgInfo.digestMethod = pkgInfoExt->digestMethod;
57     upgradePackageInfo->pkgInfo.signMethod = pkgInfoExt->signMethod;
58     upgradePackageInfo->pkgInfo.entryCount = pkgInfoExt->entryCount;
59     upgradePackageInfo->pkgInfo.pkgType = PKG_PACK_TYPE_UPGRADE;
60     files.resize(pkgInfoExt->entryCount);
61     for (uint32_t i = 0; i < pkgInfoExt->entryCount; i++) {
62         files[i].first.assign(compInfo[i].filePath);
63         ComponentInfo* info = &files[i].second;
64         if (memcpy_s(info->digest, sizeof(info->digest), compInfo[i].digest, sizeof(info->digest)) != EOK) {
65             LOG(ERROR) << "GetUpgradePkgInfo memcpy failed";
66             return PKG_NONE_MEMORY;
67         }
68         info->fileInfo.identity.assign(compInfo[i].componentAddr);
69         info->fileInfo.unpackedSize = compInfo[i].size;
70         info->fileInfo.packedSize = compInfo[i].size;
71         info->fileInfo.packMethod = PKG_COMPRESS_METHOD_NONE;
72         info->fileInfo.digestMethod = pkgInfoExt->digestMethod;
73         info->version.assign(compInfo[i].version);
74         info->id = compInfo[i].id;
75         info->resType = compInfo[i].resType;
76         info->type = compInfo[i].type;
77         info->originalSize = compInfo[i].originalSize;
78         info->compFlags = compInfo[i].flags;
79     }
80     return PKG_SUCCESS;
81 }
82 
GetZipPkgInfo(PkgManager::PkgInfoPtr pkgInfo, std::vector<std::pair<std::string, ZipFileInfo>> &files, const UpgradePkgInfoExt *pkgInfoExt, std::vector<ComponentInfoExt> &compInfo)83 int32_t GetZipPkgInfo(PkgManager::PkgInfoPtr pkgInfo,
84     std::vector<std::pair<std::string, ZipFileInfo>> &files,
85     const UpgradePkgInfoExt *pkgInfoExt,
86     std::vector<ComponentInfoExt> &compInfo)
87 {
88     if (pkgInfoExt->entryCount > MAX_ENTRY_COUNT) {
89         LOG(ERROR) << "entry count oversized " << pkgInfoExt->entryCount << ", " << MAX_ENTRY_COUNT;
90         return PKG_INVALID_PARAM;
91     }
92 
93     pkgInfo->signMethod = pkgInfoExt->signMethod;
94     pkgInfo->digestMethod  = pkgInfoExt->digestMethod;
95     pkgInfo->entryCount = pkgInfoExt->entryCount;
96     pkgInfo->pkgType = pkgInfoExt->pkgType;
97     files.resize(pkgInfoExt->entryCount);
98     for (uint32_t i = 0; i < pkgInfo->entryCount; i++) {
99         files[i].first.assign(compInfo[i].filePath);
100         ZipFileInfo* info = &files[i].second;
101         info->fileInfo.identity.assign(compInfo[i].componentAddr);
102         info->fileInfo.packMethod = PKG_COMPRESS_METHOD_ZIP;
103         info->fileInfo.digestMethod = PKG_DIGEST_TYPE_CRC;
104     }
105     return PKG_SUCCESS;
106 }
107 
GetLz4PkgInfo(PkgManager::PkgInfoPtr pkgInfo, std::vector<std::pair<std::string, Lz4FileInfo>> &files, const UpgradePkgInfoExt *pkgInfoExt, std::vector<ComponentInfoExt> &compInfo)108 int32_t GetLz4PkgInfo(PkgManager::PkgInfoPtr pkgInfo,
109     std::vector<std::pair<std::string, Lz4FileInfo>> &files,
110     const UpgradePkgInfoExt *pkgInfoExt,
111     std::vector<ComponentInfoExt> &compInfo)
112 {
113     if (pkgInfoExt->entryCount > MAX_ENTRY_COUNT) {
114         LOG(ERROR) << "entry count oversized " << pkgInfoExt->entryCount << ", " << MAX_ENTRY_COUNT;
115         return PKG_INVALID_PARAM;
116     }
117 
118     pkgInfo->signMethod = pkgInfoExt->signMethod;
119     pkgInfo->digestMethod  = pkgInfoExt->digestMethod;
120     pkgInfo->entryCount = pkgInfoExt->entryCount;
121     pkgInfo->pkgType = PKG_PACK_TYPE_LZ4;
122     files.resize(pkgInfoExt->entryCount);
123     for (uint32_t i = 0; i < pkgInfoExt->entryCount; i++) {
124         files[i].first.assign(compInfo[i].filePath);
125         Lz4FileInfo* info = &files[i].second;
126         info->fileInfo.identity.assign(compInfo[i].componentAddr);
127         info->fileInfo.packMethod = PKG_COMPRESS_METHOD_LZ4;
128         info->fileInfo.digestMethod = PKG_DIGEST_TYPE_CRC;
129         info->compressionLevel = MID_COMPRESS_LEVEL;
130         info->blockSizeID = 0;
131         info->contentChecksumFlag = 0;
132         info->blockIndependence = 0;
133     }
134     return PKG_SUCCESS;
135 }
136 }
137 
CreatePackage(const UpgradePkgInfoExt *pkgInfoExt, std::vector<ComponentInfoExt> &compInfo, const char *path, const char *keyPath)138 int32_t CreatePackage(const UpgradePkgInfoExt *pkgInfoExt,
139     std::vector<ComponentInfoExt> &compInfo,
140     const char *path,
141     const char *keyPath)
142 {
143     if (pkgInfoExt == nullptr || path == nullptr || keyPath == nullptr || pkgInfoExt->entryCount > compInfo.size()) {
144         LOG(ERROR) << "Check param fail ";
145         return PKG_INVALID_PARAM;
146     }
147     PkgManager::PkgManagerPtr manager = PkgManager::CreatePackageInstance();
148     if (manager == nullptr) {
149         LOG(ERROR) << "CreatePackageInstance fail ";
150         return PKG_INVALID_PARAM;
151     }
152 
153     int32_t ret = PKG_SUCCESS;
154     switch (pkgInfoExt->pkgType) {
155         case PKG_PACK_TYPE_UPGRADE: {
156             UpgradePkgInfo upgradePackageInfo;
157             std::vector<std::pair<std::string, ComponentInfo>> files;
158             ret = GetUpgradePkgInfo(&upgradePackageInfo, files, pkgInfoExt, compInfo);
159             if (ret == PKG_SUCCESS) {
160                 ret = manager->CreatePackage(path, keyPath, &upgradePackageInfo.pkgInfo, files);
161             }
162             break;
163         }
164         case PKG_PACK_TYPE_ZIP:
165         case PKG_PACK_TYPE_GZIP: {
166             PkgInfo info;
167             std::vector<std::pair<std::string, ZipFileInfo>> files;
168             ret = GetZipPkgInfo(&info, files, pkgInfoExt, compInfo);
169             if (ret == PKG_SUCCESS) {
170                 ret = manager->CreatePackage(path, keyPath, &info, files);
171             }
172             break;
173         }
174         case PKG_PACK_TYPE_LZ4: {
175             PkgInfo info;
176             std::vector<std::pair<std::string, Lz4FileInfo>> files;
177             ret = GetLz4PkgInfo(&info, files, pkgInfoExt, compInfo);
178             if (ret == PKG_SUCCESS) {
179                 ret = manager->CreatePackage(path, keyPath, &info, files);
180             }
181             break;
182         }
183         default:
184             ret = PKG_INVALID_PARAM;
185             break;
186     }
187     PkgManager::ReleasePackageInstance(manager);
188     return ret;
189 }
190 
VerifyPackage(const char *packagePath, const char *keyPath, const char *version, const uint8_t *digest, size_t size)191 int32_t VerifyPackage(const char *packagePath,
192     const char *keyPath,
193     const char *version,
194     const uint8_t *digest,
195     size_t size)
196 {
197     if (packagePath == nullptr || keyPath == nullptr || version == nullptr) {
198         LOG(ERROR) << "Check param fail";
199         return PKG_INVALID_PARAM;
200     }
201     PkgManager::PkgManagerPtr manager = PkgManager::CreatePackageInstance();
202     if (manager == nullptr) {
203         LOG(ERROR) << "CreatePackageInstance fail";
204         return PKG_INVALID_PARAM;
205     }
206 
207     PkgBuffer digestBuffer(const_cast<uint8_t*>(digest), size);
208     int32_t ret = manager->VerifyPackage(packagePath, keyPath, version, digestBuffer,
209         [](int32_t result, uint32_t percent) {});
210     PkgManager::ReleasePackageInstance(manager);
211     return ret;
212 }
213 
VerifyPackageWithCallback(const std::string &packagePath, const std::string &keyPath, std::function<void(int32_t result, uint32_t percent)> cb)214 int32_t VerifyPackageWithCallback(const std::string &packagePath,
215     const std::string &keyPath, std::function<void(int32_t result, uint32_t percent)> cb)
216 {
217     if (packagePath.empty() || keyPath.empty() || cb == nullptr) {
218         return PKG_INVALID_PARAM;
219     }
220 
221     PkgManager *manager = PkgManager::CreatePackageInstance();
222     if (manager == nullptr) {
223         LOG(ERROR) << "CreatePackageInstance fail";
224         return PKG_INVALID_PARAM;
225     }
226     PkgBuffer digestBuffer {};
227     std::string version {};
228     int32_t ret = manager->VerifyPackage(packagePath, keyPath, version, digestBuffer, cb);
229     if (ret != 0) {
230         cb(ret, VERIFY_FINSH_PERCENT);
231     }
232     PkgManager::ReleasePackageInstance(manager);
233     return ret;
234 }
235 
ExtraPackageDir(const char *packagePath, [[maybe_unused]] const char *keyPath, const char *dir, const char *outPath)236 int32_t ExtraPackageDir(const char *packagePath, [[maybe_unused]] const char *keyPath, const char *dir,
237     const char *outPath)
238 {
239     if (packagePath == nullptr || outPath == nullptr) {
240         LOG(ERROR) << "Check param fail ";
241         return PKG_INVALID_PARAM;
242     }
243     PkgManager::PkgManagerPtr manager = PkgManager::CreatePackageInstance();
244     if (manager == nullptr) {
245         LOG(ERROR) << "CreatePackageInstance fail ";
246         return PKG_INVALID_PARAM;
247     }
248 
249     std::vector<std::string> components;
250     int32_t ret = manager->LoadPackageWithoutUnPack(std::string(packagePath), components);
251     if (ret != PKG_SUCCESS) {
252         LOG(ERROR) << "LoadPackageWithoutUnPack fail";
253         PkgManager::ReleasePackageInstance(manager);
254         return ret;
255     }
256 
257     for (size_t i = 0; i < components.size(); i++) {
258         if (dir != nullptr && components[i].compare(0, strlen(dir), dir) != 0) {
259             continue;
260         }
261         PkgManager::StreamPtr outStream = nullptr;
262         manager->CreatePkgStream(outStream, std::string(outPath) + components[i], 0, PkgStream::PkgStreamType_Write);
263         if (outStream == nullptr) {
264             LOG(ERROR) << "CreatePkgStream fail";
265             PkgManager::ReleasePackageInstance(manager);
266             return PKG_INVALID_STREAM;
267         }
268         manager->ExtractFile(components[i], outStream);
269         manager->ClosePkgStream(outStream);
270     }
271     PkgManager::ReleasePackageInstance(manager);
272     return PKG_SUCCESS;
273 }
274 
ExtraPackageFile(const char *packagePath, [[maybe_unused]] const char *keyPath, const char *file, const char *outPath)275 int32_t ExtraPackageFile(const char *packagePath, [[maybe_unused]] const char *keyPath, const char *file,
276     const char *outPath)
277 {
278     if (packagePath == nullptr || outPath == nullptr || file == nullptr) {
279         LOG(ERROR) << "Check param fail ";
280         return PKG_INVALID_PARAM;
281     }
282 
283     PkgManager::PkgManagerPtr manager = PkgManager::CreatePackageInstance();
284     if (manager == nullptr) {
285         LOG(ERROR) << "Check param fail ";
286         return PKG_INVALID_PARAM;
287     }
288 
289     std::vector<std::string> components;
290     int32_t ret = manager->LoadPackageWithoutUnPack(std::string(packagePath), components);
291     if (ret != PKG_SUCCESS) {
292         LOG(ERROR) << "LoadPackageWithoutUnPack fail";
293         PkgManager::ReleasePackageInstance(manager);
294         return ret;
295     }
296 
297     PkgManager::StreamPtr outStream = nullptr;
298     manager->CreatePkgStream(outStream, std::string(outPath) + file, 0, PkgStream::PkgStreamType_Write);
299     if (outStream == nullptr) {
300         LOG(ERROR) << "CreatePkgStream fail";
301         PkgManager::ReleasePackageInstance(manager);
302         return PKG_INVALID_STREAM;
303     }
304     manager->ExtractFile(file, outStream);
305 
306     manager->ClosePkgStream(outStream);
307     PkgManager::ReleasePackageInstance(manager);
308     return PKG_SUCCESS;
309 }
310