• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     PKG_LOGI("is old sig support %d", isOldSigSupport_);
127     // normal mode currently do not support this signature format. skip this check to save time
128     ret = isOldSigSupport_ ? HashCheck(pkgStream, srcDataLen, hash, path) : PKG_INVALID_DIGEST;
129     if (ret != PKG_SUCCESS) {
130         srcDataLen = pkgStream->GetFileLength() - signatureSize - ZIP_EOCD_FIXED_PART_LEN;
131         ret = HashCheck(pkgStream, srcDataLen, hash, path);
132     }
133     if (ret == PKG_SUCCESS) {
134         UPDATER_CLEAR_RECORD;
135     }
136     PKG_LOGI("verify package signature %s", ret == PKG_SUCCESS ? "successfull" : "failed");
137     return ret;
138 }
139 
GetSignature(const PkgStreamPtr pkgStream,size_t & signatureSize,std::vector<uint8_t> & signature,uint16_t & commentTotalLenAll) const140 int32_t PkgVerifyUtil::GetSignature(const PkgStreamPtr pkgStream, size_t &signatureSize,
141     std::vector<uint8_t> &signature, uint16_t &commentTotalLenAll) const
142 {
143     Updater::UPDATER_INIT_RECORD;
144     size_t signatureStart = 0;
145     int32_t ret = ParsePackage(pkgStream, signatureStart, signatureSize, commentTotalLenAll);
146     if (ret != PKG_SUCCESS || signatureSize < PKG_FOOTER_SIZE) {
147         PKG_LOGE("Parse package failed.");
148         UPDATER_LAST_WORD(-1, "Parse package failed.");
149         return -1;
150     }
151 
152     size_t signDataLen = signatureSize - PKG_FOOTER_SIZE;
153     PkgBuffer signData(signDataLen);
154     size_t readLen = 0;
155     ret = pkgStream->Read(signData, signatureStart, signDataLen, readLen);
156     if (ret != PKG_SUCCESS) {
157         PKG_LOGE("read signature failed %s", pkgStream->GetFileName().c_str());
158         UPDATER_LAST_WORD(ret, "read signature failed " + pkgStream->GetFileName());
159         return ret;
160     }
161     signature.assign(signData.buffer, signData.buffer + readLen);
162 
163     size_t fileLen = pkgStream->GetFileLength();
164     if (fileLen < (signatureSize + ZIP_EOCD_FIXED_PART_LEN)) {
165         PKG_LOGE("Invalid fileLen[%zu] and signature size[%zu]", fileLen, signatureSize);
166         UPDATER_LAST_WORD(PKG_INVALID_PARAM, fileLen, signatureSize);
167         return PKG_INVALID_PARAM;
168     }
169 
170     return PKG_SUCCESS;
171 }
172 
ParsePackage(const PkgStreamPtr pkgStream,size_t & signatureStart,size_t & signatureSize,uint16_t & commentTotalLenAll) const173 int32_t PkgVerifyUtil::ParsePackage(const PkgStreamPtr pkgStream, size_t &signatureStart,
174     size_t &signatureSize, uint16_t &commentTotalLenAll) const
175 {
176     Updater::UPDATER_INIT_RECORD;
177     ZipPkgParse zipParse;
178     PkgSignComment pkgSignComment {};
179     int32_t ret = zipParse.ParseZipPkg(pkgStream, pkgSignComment);
180     if (ret != PKG_SUCCESS) {
181         PKG_LOGE("Parse zip package signature failed.");
182         UPDATER_LAST_WORD(ret);
183         return ret;
184     }
185     signatureStart = pkgStream->GetFileLength() - pkgSignComment.signCommentAppendLen;
186     signatureSize = pkgSignComment.signCommentAppendLen;
187     commentTotalLenAll = pkgSignComment.signCommentTotalLen;
188 
189     return PKG_SUCCESS;
190 }
191 
Pkcs7verify(std::vector<uint8_t> & signature,std::vector<uint8_t> & hash) const192 int32_t PkgVerifyUtil::Pkcs7verify(std::vector<uint8_t> &signature, std::vector<uint8_t> &hash) const
193 {
194     Pkcs7SignedData pkcs7;
195 
196     return pkcs7.GetHashFromSignBlock(signature.data(), signature.size(), hash);
197 }
198 
GetPkgTime(const std::string & pkgPath) const199 std::string PkgVerifyUtil::GetPkgTime(const std::string &pkgPath) const
200 {
201     struct stat statInfo {};
202     std::string fileInfo = "valid info";
203     if (stat(pkgPath.c_str(), &statInfo) != 0) {
204         PKG_LOGE("get file info error");
205     } else {
206         fileInfo = "pkg size is " + std::to_string(statInfo.st_size) +
207             " , pkg last change time is " + ctime(&statInfo.st_mtime);
208         PKG_LOGI(fileInfo.c_str());
209     }
210     return fileInfo;
211 }
212 
WriteHash(std::vector<uint8_t> & hash,const std::string & pkgPath) const213 void PkgVerifyUtil::WriteHash(std::vector<uint8_t> &hash, const std::string &pkgPath) const
214 {
215     Updater::UPDATER_INIT_RECORD;
216     std::string path = "/data/updater/hash_file";
217     if (access(path.c_str(), F_OK) != 0) {
218         std::ofstream file(path, std::ios::out);
219         if (!file) {
220             PKG_LOGE("open file failed");
221             return;
222         }
223         file.write(reinterpret_cast<char *>(hash.data()), sizeof(hash));
224         return;
225     }
226     std::ifstream file(path, std::ios::in);
227     if (!file) {
228         PKG_LOGE("open file failed");
229         return;
230     }
231     std::string lastHash {};
232     if (getline(file, lastHash)) {
233         std::vector<unsigned char> lastHashVector {};
234         lastHashVector.assign(lastHash.begin(), lastHash.end());
235         UPDATER_LAST_WORD(ConvertShaHex(static_cast<std::vector<uint8_t>>(lastHashVector)),
236                           ConvertShaHex(hash), GetPkgTime(pkgPath));
237     }
238 }
239 
HashCheck(const PkgStreamPtr srcData,const size_t dataLen,const std::vector<uint8_t> & hash,const std::string & path) const240 int32_t PkgVerifyUtil::HashCheck(const PkgStreamPtr srcData, const size_t dataLen,
241     const std::vector<uint8_t> &hash, const std::string &path) const
242 {
243     Updater::UPDATER_INIT_RECORD;
244     std::string fileInfo = GetPkgTime(path);
245     if (srcData == nullptr || dataLen == 0) {
246         UPDATER_LAST_WORD(PKG_INVALID_PARAM);
247         return PKG_INVALID_PARAM;
248     }
249 
250     size_t digestLen = hash.size();
251     if (digestLen != PKG_HASH_CONTENT_LEN) {
252         PKG_LOGE("calc pkg sha256 digest failed.");
253         UPDATER_LAST_WORD(PKG_INVALID_PARAM, fileInfo);
254         return PKG_INVALID_PARAM;
255     }
256     std::vector<uint8_t> sourceDigest(digestLen);
257     int32_t ret = CalcSha256Digest(srcData, dataLen, sourceDigest);
258     if (ret != PKG_SUCCESS) {
259         PKG_LOGE("calc pkg sha256 digest failed.");
260         UPDATER_LAST_WORD(ret, fileInfo);
261         return ret;
262     }
263 
264     if (memcmp(hash.data(), sourceDigest.data(), digestLen) != EOK) {
265         PKG_LOGW("Failed to memcmp data.");
266         UPDATER_LAST_WORD(PKG_INVALID_DIGEST,
267                           ConvertShaHex(hash).substr(0, INTERCEPT_HASH_LENGTH),
268                           ConvertShaHex(sourceDigest).substr(0, INTERCEPT_HASH_LENGTH), fileInfo);
269         WriteHash(sourceDigest, path);
270         return PKG_INVALID_DIGEST;
271     }
272 
273     return PKG_SUCCESS;
274 }
275 } // namespace Hpackage
276