1 /*
2 * Copyright (c) 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 "pkg_verify_util.h"
17 #include <ctime>
18 #include <sys/stat.h>
19 #include <unistd.h>
20 #include "dump.h"
21 #include "openssl_util.h"
22 #include "pkcs7_signed_data.h"
23 #include "pkg_algo_sign.h"
24 #include "pkg_algorithm.h"
25 #include "pkg_manager_impl.h"
26 #include "pkg_utils.h"
27 #include "securec.h"
28 #include "zip_pkg_parse.h"
29
30 namespace Hpackage {
31 namespace {
32 constexpr uint32_t ZIP_EOCD_FIXED_PART_LEN = 22;
33 constexpr uint32_t PKG_FOOTER_SIZE = 6;
34 constexpr uint32_t PKG_HASH_CONTENT_LEN = SHA256_DIGEST_LENGTH;
35 constexpr uint32_t INTERCEPT_HASH_LENGTH = 8;
36 }
37
VerifySourceDigest(std::vector<uint8_t> & signature,std::vector<uint8_t> & sourceDigest,const std::string & keyPath) const38 int32_t PkgVerifyUtil::VerifySourceDigest(std::vector<uint8_t> &signature, std::vector<uint8_t> &sourceDigest,
39 const std::string & keyPath) const
40 {
41 Updater::UPDATER_INIT_RECORD;
42 std::vector<std::vector<uint8_t>> sigs;
43 Pkcs7SignedData pkcs7;
44 SignAlgorithm::SignAlgorithmPtr signAlgorithm = PkgAlgorithmFactory::GetVerifyAlgorithm(
45 keyPath, PKG_DIGEST_TYPE_SHA256);
46 int32_t ret = pkcs7.ReadSig(signature.data(), signature.size(), sigs);
47 if (ret != PKCS7_SUCCESS) {
48 UPDATER_LAST_WORD("pkcs7", ret);
49 return ret;
50 }
51 for (auto &sig : sigs) {
52 if (signAlgorithm->VerifyDigest(sourceDigest, sig) == 0) {
53 return PKG_SUCCESS;
54 }
55 }
56 return PKG_VERIFY_FAIL;
57 }
58
VerifyAccPackageSign(const PkgStreamPtr pkgStream,const std::string & keyPath) const59 int32_t PkgVerifyUtil::VerifyAccPackageSign(const PkgStreamPtr pkgStream, const std::string &keyPath) const
60 {
61 Updater::UPDATER_INIT_RECORD;
62 if (pkgStream == nullptr) {
63 UPDATER_LAST_WORD(PKG_INVALID_PARAM, "pkgStream is null");
64 return PKG_INVALID_PARAM;
65 }
66 size_t signatureSize = 0;
67 std::vector<uint8_t> signature;
68 uint16_t commentTotalLenAll = 0;
69 if (GetSignature(pkgStream, signatureSize, signature, commentTotalLenAll) != PKG_SUCCESS) {
70 PKG_LOGE("get package signature fail!");
71 UPDATER_LAST_WORD(PKG_INVALID_SIGNATURE, "get package signature fail!");
72 return PKG_INVALID_SIGNATURE;
73 }
74 size_t srcDataLen = pkgStream->GetFileLength() - commentTotalLenAll -2;
75 size_t readLen = 0;
76 std::vector<uint8_t> sourceDigest;
77 PkgBuffer digest(srcDataLen);
78 pkgStream->Read(digest, 0, srcDataLen, readLen);
79 sourceDigest.assign(digest.buffer, digest.buffer + readLen);
80 return VerifySourceDigest(signature, sourceDigest, keyPath);
81 }
82
VerifySign(std::vector<uint8_t> & signData,std::vector<uint8_t> & digest) const83 int32_t PkgVerifyUtil::VerifySign(std::vector<uint8_t> &signData, std::vector<uint8_t> &digest) const
84 {
85 Updater::UPDATER_INIT_RECORD;
86 std::vector<uint8_t> hash;
87 int32_t ret = Pkcs7verify(signData, hash);
88 if (ret != PKG_SUCCESS) {
89 PKG_LOGE("pkcs7 verify fail!");
90 UPDATER_LAST_WORD(ret, "pkcs7 verify fail!");
91 return ret;
92 }
93 size_t hashLen = hash.size();
94 if ((hashLen != digest.size()) || memcmp(hash.data(), digest.data(), hashLen) != EOK) {
95 PKG_LOGE("Failed to memcmp data.");
96 UPDATER_LAST_WORD(PKG_INVALID_DIGEST, "Failed to memcmp data.");
97 return PKG_INVALID_DIGEST;
98 }
99 return PKG_SUCCESS;
100 }
101
VerifyPackageSign(const PkgStreamPtr pkgStream,const std::string & path) const102 int32_t PkgVerifyUtil::VerifyPackageSign(const PkgStreamPtr pkgStream, const std::string &path) const
103 {
104 Updater::UPDATER_INIT_RECORD;
105 if (pkgStream == nullptr) {
106 UPDATER_LAST_WORD(PKG_INVALID_PARAM, "pkgStream is null");
107 return PKG_INVALID_PARAM;
108 }
109 size_t signatureSize = 0;
110 std::vector<uint8_t> signature;
111 uint16_t commentTotalLenAll = 0;
112 if (GetSignature(pkgStream, signatureSize, signature, commentTotalLenAll) != PKG_SUCCESS) {
113 PKG_LOGE("get package signature fail!");
114 UPDATER_LAST_WORD(PKG_INVALID_SIGNATURE, "get package signature fail!");
115 return PKG_INVALID_SIGNATURE;
116 }
117
118 std::vector<uint8_t> hash;
119 int32_t ret = Pkcs7verify(signature, hash);
120 if (ret != PKG_SUCCESS) {
121 PKG_LOGE("pkcs7 verify fail!");
122 UPDATER_LAST_WORD(ret, "pkcs7 verify fail!");
123 return ret;
124 }
125 size_t srcDataLen = pkgStream->GetFileLength() - commentTotalLenAll - 2;
126
127 ret = HashCheck(pkgStream, srcDataLen, hash, path);
128 if (ret != PKG_SUCCESS) {
129 srcDataLen = pkgStream->GetFileLength() - signatureSize - ZIP_EOCD_FIXED_PART_LEN;
130 ret = HashCheck(pkgStream, srcDataLen, hash, path);
131 }
132 if (ret == PKG_SUCCESS) {
133 UPDATER_CLEAR_RECORD;
134 }
135 PKG_LOGI("verify package signature %s", ret == PKG_SUCCESS ? "successfull" : "failed");
136 return ret;
137 }
138
GetSignature(const PkgStreamPtr pkgStream,size_t & signatureSize,std::vector<uint8_t> & signature,uint16_t & commentTotalLenAll) const139 int32_t PkgVerifyUtil::GetSignature(const PkgStreamPtr pkgStream, size_t &signatureSize,
140 std::vector<uint8_t> &signature, uint16_t &commentTotalLenAll) const
141 {
142 Updater::UPDATER_INIT_RECORD;
143 size_t signatureStart = 0;
144 int32_t ret = ParsePackage(pkgStream, signatureStart, signatureSize, commentTotalLenAll);
145 if (ret != PKG_SUCCESS || signatureSize < PKG_FOOTER_SIZE) {
146 PKG_LOGE("Parse package failed.");
147 UPDATER_LAST_WORD(-1, "Parse package failed.");
148 return -1;
149 }
150
151 size_t signDataLen = signatureSize - PKG_FOOTER_SIZE;
152 PkgBuffer signData(signDataLen);
153 size_t readLen = 0;
154 ret = pkgStream->Read(signData, signatureStart, signDataLen, readLen);
155 if (ret != PKG_SUCCESS) {
156 PKG_LOGE("read signature failed %s", pkgStream->GetFileName().c_str());
157 UPDATER_LAST_WORD(ret, "read signature failed " + pkgStream->GetFileName());
158 return ret;
159 }
160 signature.assign(signData.buffer, signData.buffer + readLen);
161
162 size_t fileLen = pkgStream->GetFileLength();
163 if (fileLen < (signatureSize + ZIP_EOCD_FIXED_PART_LEN)) {
164 PKG_LOGE("Invalid fileLen[%zu] and signature size[%zu]", fileLen, signatureSize);
165 UPDATER_LAST_WORD(PKG_INVALID_PARAM, fileLen, signatureSize);
166 return PKG_INVALID_PARAM;
167 }
168
169 return PKG_SUCCESS;
170 }
171
ParsePackage(const PkgStreamPtr pkgStream,size_t & signatureStart,size_t & signatureSize,uint16_t & commentTotalLenAll) const172 int32_t PkgVerifyUtil::ParsePackage(const PkgStreamPtr pkgStream, size_t &signatureStart,
173 size_t &signatureSize, uint16_t &commentTotalLenAll) const
174 {
175 Updater::UPDATER_INIT_RECORD;
176 ZipPkgParse zipParse;
177 PkgSignComment pkgSignComment {};
178 int32_t ret = zipParse.ParseZipPkg(pkgStream, pkgSignComment);
179 if (ret != PKG_SUCCESS) {
180 PKG_LOGE("Parse zip package signature failed.");
181 UPDATER_LAST_WORD(ret);
182 return ret;
183 }
184 signatureStart = pkgStream->GetFileLength() - pkgSignComment.signCommentAppendLen;
185 signatureSize = pkgSignComment.signCommentAppendLen;
186 commentTotalLenAll = pkgSignComment.signCommentTotalLen;
187
188 return PKG_SUCCESS;
189 }
190
Pkcs7verify(std::vector<uint8_t> & signature,std::vector<uint8_t> & hash) const191 int32_t PkgVerifyUtil::Pkcs7verify(std::vector<uint8_t> &signature, std::vector<uint8_t> &hash) const
192 {
193 Pkcs7SignedData pkcs7;
194
195 return pkcs7.GetHashFromSignBlock(signature.data(), signature.size(), hash);
196 }
197
GetPkgTime(const std::string & pkgPath) const198 std::string PkgVerifyUtil::GetPkgTime(const std::string &pkgPath) const
199 {
200 struct stat statInfo {};
201 std::string fileInfo = "valid info";
202 if (stat(pkgPath.c_str(), &statInfo) != 0) {
203 PKG_LOGE("get file info error");
204 } else {
205 fileInfo = "pkg size is " + std::to_string(statInfo.st_size) +
206 " , pkg last change time is " + ctime(&statInfo.st_mtime);
207 PKG_LOGI(fileInfo.c_str());
208 }
209 return fileInfo;
210 }
211
WriteHash(std::vector<uint8_t> & hash,const std::string & pkgPath) const212 void PkgVerifyUtil::WriteHash(std::vector<uint8_t> &hash, const std::string &pkgPath) const
213 {
214 Updater::UPDATER_INIT_RECORD;
215 std::string path = "/data/updater/hash_file";
216 if (access(path.c_str(), F_OK) != 0) {
217 std::ofstream file(path, std::ios::out);
218 if (!file) {
219 PKG_LOGE("open file failed");
220 return;
221 }
222 file.write(reinterpret_cast<char *>(hash.data()), sizeof(hash));
223 return;
224 }
225 std::ifstream file(path, std::ios::in);
226 if (!file) {
227 PKG_LOGE("open file failed");
228 return;
229 }
230 std::string lastHash {};
231 if (getline(file, lastHash)) {
232 std::vector<unsigned char> lastHashVector {};
233 lastHashVector.assign(lastHash.begin(), lastHash.end());
234 UPDATER_LAST_WORD(ConvertShaHex(static_cast<std::vector<uint8_t>>(lastHashVector)),
235 ConvertShaHex(hash), GetPkgTime(pkgPath));
236 }
237 }
238
HashCheck(const PkgStreamPtr srcData,const size_t dataLen,const std::vector<uint8_t> & hash,const std::string & path) const239 int32_t PkgVerifyUtil::HashCheck(const PkgStreamPtr srcData, const size_t dataLen,
240 const std::vector<uint8_t> &hash, const std::string &path) const
241 {
242 Updater::UPDATER_INIT_RECORD;
243 std::string fileInfo = GetPkgTime(path);
244 if (srcData == nullptr || dataLen == 0) {
245 UPDATER_LAST_WORD(PKG_INVALID_PARAM);
246 return PKG_INVALID_PARAM;
247 }
248
249 size_t digestLen = hash.size();
250 if (digestLen != PKG_HASH_CONTENT_LEN) {
251 PKG_LOGE("calc pkg sha256 digest failed.");
252 UPDATER_LAST_WORD(PKG_INVALID_PARAM, fileInfo);
253 return PKG_INVALID_PARAM;
254 }
255 std::vector<uint8_t> sourceDigest(digestLen);
256 int32_t ret = CalcSha256Digest(srcData, dataLen, sourceDigest);
257 if (ret != PKG_SUCCESS) {
258 PKG_LOGE("calc pkg sha256 digest failed.");
259 UPDATER_LAST_WORD(ret, fileInfo);
260 return ret;
261 }
262
263 if (memcmp(hash.data(), sourceDigest.data(), digestLen) != EOK) {
264 PKG_LOGW("Failed to memcmp data.");
265 UPDATER_LAST_WORD(PKG_INVALID_DIGEST,
266 ConvertShaHex(hash).substr(0, INTERCEPT_HASH_LENGTH),
267 ConvertShaHex(sourceDigest).substr(0, INTERCEPT_HASH_LENGTH), fileInfo);
268 WriteHash(sourceDigest, path);
269 return PKG_INVALID_DIGEST;
270 }
271
272 return PKG_SUCCESS;
273 }
274 } // namespace Hpackage
275