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 <unistd.h>
18 #include "dump.h"
19 #include "openssl_util.h"
20 #include "pkcs7_signed_data.h"
21 #include "pkg_algo_sign.h"
22 #include "pkg_algorithm.h"
23 #include "pkg_manager_impl.h"
24 #include "pkg_utils.h"
25 #include "securec.h"
26 #include "zip_pkg_parse.h"
27
28 namespace Hpackage {
29 namespace {
30 constexpr uint32_t ZIP_EOCD_FIXED_PART_LEN = 22;
31 constexpr uint32_t PKG_FOOTER_SIZE = 6;
32 constexpr uint32_t PKG_HASH_CONTENT_LEN = SHA256_DIGEST_LENGTH;
33 }
34
VerifySourceDigest(std::vector<uint8_t> &signature, std::vector<uint8_t> &sourceDigest, const std::string & keyPath) const35 int32_t PkgVerifyUtil::VerifySourceDigest(std::vector<uint8_t> &signature, std::vector<uint8_t> &sourceDigest,
36 const std::string & keyPath) const
37 {
38 std::vector<std::vector<uint8_t>> sigs;
39 Pkcs7SignedData pkcs7;
40 SignAlgorithm::SignAlgorithmPtr signAlgorithm = PkgAlgorithmFactory::GetVerifyAlgorithm(
41 keyPath, PKG_DIGEST_TYPE_SHA256);
42 int32_t ret = pkcs7.ReadSig(signature.data(), signature.size(), sigs);
43 if (ret != PKCS7_SUCCESS) {
44 UPDATER_LAST_WORD("pkcs7", ret);
45 return ret;
46 }
47 for (auto &sig : sigs) {
48 if (signAlgorithm->VerifyDigest(sourceDigest, sig) == 0) {
49 return PKG_SUCCESS;
50 }
51 }
52 return PKG_VERIFY_FAIL;
53 }
54
VerifyAccPackageSign(const PkgStreamPtr pkgStream, const std::string &keyPath) const55 int32_t PkgVerifyUtil::VerifyAccPackageSign(const PkgStreamPtr pkgStream, const std::string &keyPath) const
56 {
57 if (pkgStream == nullptr) {
58 UPDATER_LAST_WORD(PKG_INVALID_PARAM);
59 return PKG_INVALID_PARAM;
60 }
61 size_t signatureSize = 0;
62 std::vector<uint8_t> signature;
63 uint16_t commentTotalLenAll = 0;
64 if (GetSignature(pkgStream, signatureSize, signature, commentTotalLenAll) != PKG_SUCCESS) {
65 PKG_LOGE("get package signature fail!");
66 UPDATER_LAST_WORD(PKG_INVALID_SIGNATURE);
67 return PKG_INVALID_SIGNATURE;
68 }
69 size_t srcDataLen = pkgStream->GetFileLength() - commentTotalLenAll -2;
70 size_t readLen = 0;
71 std::vector<uint8_t> sourceDigest;
72 PkgBuffer digest(srcDataLen);
73 pkgStream->Read(digest, 0, srcDataLen, readLen);
74 sourceDigest.assign(digest.buffer, digest.buffer + readLen);
75 return VerifySourceDigest(signature, sourceDigest, keyPath);
76 }
77
VerifySign(std::vector<uint8_t> &signData, std::vector<uint8_t> &digest) const78 int32_t PkgVerifyUtil::VerifySign(std::vector<uint8_t> &signData, std::vector<uint8_t> &digest) const
79 {
80 std::vector<uint8_t> hash;
81 int32_t ret = Pkcs7verify(signData, hash);
82 if (ret != PKG_SUCCESS) {
83 PKG_LOGE("pkcs7 verify fail!");
84 UPDATER_LAST_WORD(ret);
85 return ret;
86 }
87 size_t hashLen = hash.size();
88 if ((hashLen != digest.size()) || memcmp(hash.data(), digest.data(), hashLen) != EOK) {
89 PKG_LOGE("Failed to memcmp data.");
90 UPDATER_LAST_WORD(PKG_INVALID_DIGEST);
91 return PKG_INVALID_DIGEST;
92 }
93 return PKG_SUCCESS;
94 }
95
VerifyPackageSign(const PkgStreamPtr pkgStream) const96 int32_t PkgVerifyUtil::VerifyPackageSign(const PkgStreamPtr pkgStream) const
97 {
98 if (pkgStream == nullptr) {
99 UPDATER_LAST_WORD(PKG_INVALID_PARAM);
100 return PKG_INVALID_PARAM;
101 }
102 size_t signatureSize = 0;
103 std::vector<uint8_t> signature;
104 uint16_t commentTotalLenAll = 0;
105 if (GetSignature(pkgStream, signatureSize, signature, commentTotalLenAll) != PKG_SUCCESS) {
106 PKG_LOGE("get package signature fail!");
107 UPDATER_LAST_WORD(PKG_INVALID_SIGNATURE);
108 return PKG_INVALID_SIGNATURE;
109 }
110
111 std::vector<uint8_t> hash;
112 int32_t ret = Pkcs7verify(signature, hash);
113 if (ret != PKG_SUCCESS) {
114 PKG_LOGE("pkcs7 verify fail!");
115 UPDATER_LAST_WORD(ret);
116 return ret;
117 }
118 size_t srcDataLen = pkgStream->GetFileLength() - commentTotalLenAll - 2;
119
120 ret = HashCheck(pkgStream, srcDataLen, hash);
121 if (ret != PKG_SUCCESS) {
122 srcDataLen = pkgStream->GetFileLength() - signatureSize - ZIP_EOCD_FIXED_PART_LEN;
123 ret = HashCheck(pkgStream, srcDataLen, hash);
124 }
125 PKG_LOGI("verify package signature %s", ret == PKG_SUCCESS ? "successfull" : "failed");
126 return ret;
127 }
128
GetSignature(const PkgStreamPtr pkgStream, size_t &signatureSize, std::vector<uint8_t> &signature, uint16_t &commentTotalLenAll) const129 int32_t PkgVerifyUtil::GetSignature(const PkgStreamPtr pkgStream, size_t &signatureSize,
130 std::vector<uint8_t> &signature, uint16_t &commentTotalLenAll) const
131 {
132 size_t signatureStart = 0;
133 int32_t ret = ParsePackage(pkgStream, signatureStart, signatureSize, commentTotalLenAll);
134 if (ret != PKG_SUCCESS || signatureSize < PKG_FOOTER_SIZE) {
135 PKG_LOGE("Parse package failed.");
136 UPDATER_LAST_WORD(-1);
137 return -1;
138 }
139
140 size_t signDataLen = signatureSize - PKG_FOOTER_SIZE;
141 PkgBuffer signData(signDataLen);
142 size_t readLen = 0;
143 ret = pkgStream->Read(signData, signatureStart, signDataLen, readLen);
144 if (ret != PKG_SUCCESS) {
145 PKG_LOGE("read signature failed %s", pkgStream->GetFileName().c_str());
146 UPDATER_LAST_WORD(ret);
147 return ret;
148 }
149 signature.assign(signData.buffer, signData.buffer + readLen);
150
151 size_t fileLen = pkgStream->GetFileLength();
152 if (fileLen < (signatureSize + ZIP_EOCD_FIXED_PART_LEN)) {
153 PKG_LOGE("Invalid fileLen[%zu] and signature size[%zu]", fileLen, signatureSize);
154 UPDATER_LAST_WORD(PKG_INVALID_PARAM, fileLen, signatureSize);
155 return PKG_INVALID_PARAM;
156 }
157
158 return PKG_SUCCESS;
159 }
160
ParsePackage(const PkgStreamPtr pkgStream, size_t &signatureStart, size_t &signatureSize, uint16_t &commentTotalLenAll) const161 int32_t PkgVerifyUtil::ParsePackage(const PkgStreamPtr pkgStream, size_t &signatureStart,
162 size_t &signatureSize, uint16_t &commentTotalLenAll) const
163 {
164 ZipPkgParse zipParse;
165 PkgSignComment pkgSignComment {};
166 int32_t ret = zipParse.ParseZipPkg(pkgStream, pkgSignComment);
167 if (ret != PKG_SUCCESS) {
168 PKG_LOGE("Parse zip package signature failed.");
169 UPDATER_LAST_WORD(ret);
170 return ret;
171 }
172 signatureStart = pkgStream->GetFileLength() - pkgSignComment.signCommentAppendLen;
173 signatureSize = pkgSignComment.signCommentAppendLen;
174 commentTotalLenAll = pkgSignComment.signCommentTotalLen;
175
176 return PKG_SUCCESS;
177 }
178
Pkcs7verify(std::vector<uint8_t> &signature, std::vector<uint8_t> &hash) const179 int32_t PkgVerifyUtil::Pkcs7verify(std::vector<uint8_t> &signature, std::vector<uint8_t> &hash) const
180 {
181 Pkcs7SignedData pkcs7;
182
183 return pkcs7.GetHashFromSignBlock(signature.data(), signature.size(), hash);
184 }
185
HashCheck(const PkgStreamPtr srcData, const size_t dataLen, const std::vector<uint8_t> &hash) const186 int32_t PkgVerifyUtil::HashCheck(const PkgStreamPtr srcData, const size_t dataLen,
187 const std::vector<uint8_t> &hash) const
188 {
189 Updater::UPDATER_INIT_RECORD;
190 if (srcData == nullptr || dataLen == 0) {
191 UPDATER_LAST_WORD(PKG_INVALID_PARAM);
192 return PKG_INVALID_PARAM;
193 }
194
195 size_t digestLen = hash.size();
196 if (digestLen != PKG_HASH_CONTENT_LEN) {
197 PKG_LOGE("calc pkg sha256 digest failed.");
198 UPDATER_LAST_WORD(PKG_INVALID_PARAM);
199 return PKG_INVALID_PARAM;
200 }
201 std::vector<uint8_t> sourceDigest(digestLen);
202 int32_t ret = CalcSha256Digest(srcData, dataLen, sourceDigest);
203 if (ret != PKG_SUCCESS) {
204 PKG_LOGE("calc pkg sha256 digest failed.");
205 UPDATER_LAST_WORD(ret);
206 return ret;
207 }
208
209 if (memcmp(hash.data(), sourceDigest.data(), digestLen) != EOK) {
210 PKG_LOGW("Failed to memcmp data.");
211 UPDATER_LAST_WORD(PKG_INVALID_DIGEST);
212 return PKG_INVALID_DIGEST;
213 }
214
215 return PKG_SUCCESS;
216 }
217 } // namespace Hpackage
218