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 }
36
VerifySourceDigest(std::vector<uint8_t> & signature,std::vector<uint8_t> & sourceDigest,const std::string & keyPath) const37 int32_t PkgVerifyUtil::VerifySourceDigest(std::vector<uint8_t> &signature, std::vector<uint8_t> &sourceDigest,
38 const std::string & keyPath) const
39 {
40 std::vector<std::vector<uint8_t>> sigs;
41 Pkcs7SignedData pkcs7;
42 SignAlgorithm::SignAlgorithmPtr signAlgorithm = PkgAlgorithmFactory::GetVerifyAlgorithm(
43 keyPath, PKG_DIGEST_TYPE_SHA256);
44 int32_t ret = pkcs7.ReadSig(signature.data(), signature.size(), sigs);
45 if (ret != PKCS7_SUCCESS) {
46 UPDATER_LAST_WORD("pkcs7", ret);
47 return ret;
48 }
49 for (auto &sig : sigs) {
50 if (signAlgorithm->VerifyDigest(sourceDigest, sig) == 0) {
51 return PKG_SUCCESS;
52 }
53 }
54 return PKG_VERIFY_FAIL;
55 }
56
VerifyAccPackageSign(const PkgStreamPtr pkgStream,const std::string & keyPath) const57 int32_t PkgVerifyUtil::VerifyAccPackageSign(const PkgStreamPtr pkgStream, const std::string &keyPath) const
58 {
59 if (pkgStream == nullptr) {
60 UPDATER_LAST_WORD(PKG_INVALID_PARAM);
61 return PKG_INVALID_PARAM;
62 }
63 size_t signatureSize = 0;
64 std::vector<uint8_t> signature;
65 uint16_t commentTotalLenAll = 0;
66 if (GetSignature(pkgStream, signatureSize, signature, commentTotalLenAll) != PKG_SUCCESS) {
67 PKG_LOGE("get package signature fail!");
68 UPDATER_LAST_WORD(PKG_INVALID_SIGNATURE);
69 return PKG_INVALID_SIGNATURE;
70 }
71 size_t srcDataLen = pkgStream->GetFileLength() - commentTotalLenAll -2;
72 size_t readLen = 0;
73 std::vector<uint8_t> sourceDigest;
74 PkgBuffer digest(srcDataLen);
75 pkgStream->Read(digest, 0, srcDataLen, readLen);
76 sourceDigest.assign(digest.buffer, digest.buffer + readLen);
77 return VerifySourceDigest(signature, sourceDigest, keyPath);
78 }
79
VerifySign(std::vector<uint8_t> & signData,std::vector<uint8_t> & digest) const80 int32_t PkgVerifyUtil::VerifySign(std::vector<uint8_t> &signData, std::vector<uint8_t> &digest) const
81 {
82 std::vector<uint8_t> hash;
83 int32_t ret = Pkcs7verify(signData, hash);
84 if (ret != PKG_SUCCESS) {
85 PKG_LOGE("pkcs7 verify fail!");
86 UPDATER_LAST_WORD(ret);
87 return ret;
88 }
89 size_t hashLen = hash.size();
90 if ((hashLen != digest.size()) || memcmp(hash.data(), digest.data(), hashLen) != EOK) {
91 PKG_LOGE("Failed to memcmp data.");
92 UPDATER_LAST_WORD(PKG_INVALID_DIGEST);
93 return PKG_INVALID_DIGEST;
94 }
95 return PKG_SUCCESS;
96 }
97
VerifyPackageSign(const PkgStreamPtr pkgStream,const std::string & path) const98 int32_t PkgVerifyUtil::VerifyPackageSign(const PkgStreamPtr pkgStream, const std::string &path) const
99 {
100 if (pkgStream == nullptr) {
101 UPDATER_LAST_WORD(PKG_INVALID_PARAM);
102 return PKG_INVALID_PARAM;
103 }
104 size_t signatureSize = 0;
105 std::vector<uint8_t> signature;
106 uint16_t commentTotalLenAll = 0;
107 if (GetSignature(pkgStream, signatureSize, signature, commentTotalLenAll) != PKG_SUCCESS) {
108 PKG_LOGE("get package signature fail!");
109 UPDATER_LAST_WORD(PKG_INVALID_SIGNATURE);
110 return PKG_INVALID_SIGNATURE;
111 }
112
113 std::vector<uint8_t> hash;
114 int32_t ret = Pkcs7verify(signature, hash);
115 if (ret != PKG_SUCCESS) {
116 PKG_LOGE("pkcs7 verify fail!");
117 UPDATER_LAST_WORD(ret);
118 return ret;
119 }
120 size_t srcDataLen = pkgStream->GetFileLength() - commentTotalLenAll - 2;
121
122 ret = HashCheck(pkgStream, srcDataLen, hash, path);
123 if (ret != PKG_SUCCESS) {
124 srcDataLen = pkgStream->GetFileLength() - signatureSize - ZIP_EOCD_FIXED_PART_LEN;
125 ret = HashCheck(pkgStream, srcDataLen, hash, path);
126 }
127 PKG_LOGI("verify package signature %s", ret == PKG_SUCCESS ? "successfull" : "failed");
128 return ret;
129 }
130
GetSignature(const PkgStreamPtr pkgStream,size_t & signatureSize,std::vector<uint8_t> & signature,uint16_t & commentTotalLenAll) const131 int32_t PkgVerifyUtil::GetSignature(const PkgStreamPtr pkgStream, size_t &signatureSize,
132 std::vector<uint8_t> &signature, uint16_t &commentTotalLenAll) const
133 {
134 size_t signatureStart = 0;
135 int32_t ret = ParsePackage(pkgStream, signatureStart, signatureSize, commentTotalLenAll);
136 if (ret != PKG_SUCCESS || signatureSize < PKG_FOOTER_SIZE) {
137 PKG_LOGE("Parse package failed.");
138 UPDATER_LAST_WORD(-1);
139 return -1;
140 }
141
142 size_t signDataLen = signatureSize - PKG_FOOTER_SIZE;
143 PkgBuffer signData(signDataLen);
144 size_t readLen = 0;
145 ret = pkgStream->Read(signData, signatureStart, signDataLen, readLen);
146 if (ret != PKG_SUCCESS) {
147 PKG_LOGE("read signature failed %s", pkgStream->GetFileName().c_str());
148 UPDATER_LAST_WORD(ret);
149 return ret;
150 }
151 signature.assign(signData.buffer, signData.buffer + readLen);
152
153 size_t fileLen = pkgStream->GetFileLength();
154 if (fileLen < (signatureSize + ZIP_EOCD_FIXED_PART_LEN)) {
155 PKG_LOGE("Invalid fileLen[%zu] and signature size[%zu]", fileLen, signatureSize);
156 UPDATER_LAST_WORD(PKG_INVALID_PARAM, fileLen, signatureSize);
157 return PKG_INVALID_PARAM;
158 }
159
160 return PKG_SUCCESS;
161 }
162
ParsePackage(const PkgStreamPtr pkgStream,size_t & signatureStart,size_t & signatureSize,uint16_t & commentTotalLenAll) const163 int32_t PkgVerifyUtil::ParsePackage(const PkgStreamPtr pkgStream, size_t &signatureStart,
164 size_t &signatureSize, uint16_t &commentTotalLenAll) const
165 {
166 ZipPkgParse zipParse;
167 PkgSignComment pkgSignComment {};
168 int32_t ret = zipParse.ParseZipPkg(pkgStream, pkgSignComment);
169 if (ret != PKG_SUCCESS) {
170 PKG_LOGE("Parse zip package signature failed.");
171 UPDATER_LAST_WORD(ret);
172 return ret;
173 }
174 signatureStart = pkgStream->GetFileLength() - pkgSignComment.signCommentAppendLen;
175 signatureSize = pkgSignComment.signCommentAppendLen;
176 commentTotalLenAll = pkgSignComment.signCommentTotalLen;
177
178 return PKG_SUCCESS;
179 }
180
Pkcs7verify(std::vector<uint8_t> & signature,std::vector<uint8_t> & hash) const181 int32_t PkgVerifyUtil::Pkcs7verify(std::vector<uint8_t> &signature, std::vector<uint8_t> &hash) const
182 {
183 Pkcs7SignedData pkcs7;
184
185 return pkcs7.GetHashFromSignBlock(signature.data(), signature.size(), hash);
186 }
187
HashCheck(const PkgStreamPtr srcData,const size_t dataLen,const std::vector<uint8_t> & hash,const std::string & path) const188 int32_t PkgVerifyUtil::HashCheck(const PkgStreamPtr srcData, const size_t dataLen,
189 const std::vector<uint8_t> &hash, const std::string &path) const
190 {
191 Updater::UPDATER_INIT_RECORD;
192 struct stat statInfo {};
193 std::string fileInfo = "valid info";
194 if (stat(path.c_str(), &statInfo) != 0) {
195 PKG_LOGE("get file info error");
196 } else {
197 fileInfo = "pkg size is " + std::to_string(statInfo.st_size) +
198 " , pkg last change time is " + ctime(&statInfo.st_mtime);
199 PKG_LOGI(fileInfo.c_str());
200 }
201 if (srcData == nullptr || dataLen == 0) {
202 UPDATER_LAST_WORD(PKG_INVALID_PARAM);
203 return PKG_INVALID_PARAM;
204 }
205
206 size_t digestLen = hash.size();
207 if (digestLen != PKG_HASH_CONTENT_LEN) {
208 PKG_LOGE("calc pkg sha256 digest failed.");
209 UPDATER_LAST_WORD(PKG_INVALID_PARAM, fileInfo);
210 return PKG_INVALID_PARAM;
211 }
212 std::vector<uint8_t> sourceDigest(digestLen);
213 int32_t ret = CalcSha256Digest(srcData, dataLen, sourceDigest);
214 if (ret != PKG_SUCCESS) {
215 PKG_LOGE("calc pkg sha256 digest failed.");
216 UPDATER_LAST_WORD(ret, fileInfo);
217 return ret;
218 }
219
220 if (memcmp(hash.data(), sourceDigest.data(), digestLen) != EOK) {
221 PKG_LOGW("Failed to memcmp data.");
222 UPDATER_LAST_WORD(PKG_INVALID_DIGEST, fileInfo);
223 return PKG_INVALID_DIGEST;
224 }
225
226 return PKG_SUCCESS;
227 }
228 } // namespace Hpackage
229