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