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_utils.h"
22 #include "securec.h"
23 #include "zip_pkg_parse.h"
24
25 namespace Hpackage {
26 namespace {
27 constexpr uint32_t ZIP_EOCD_FIXED_PART_LEN = 22;
28 constexpr uint32_t PKG_FOOTER_SIZE = 6;
29 constexpr uint32_t PKG_HASH_CONTENT_LEN = SHA256_DIGEST_LENGTH;
30 }
31
VerifyPackageSign(const PkgStreamPtr pkgStream) const32 int32_t PkgVerifyUtil::VerifyPackageSign(const PkgStreamPtr pkgStream) const
33 {
34 if (pkgStream == nullptr) {
35 UPDATER_LAST_WORD(PKG_INVALID_PARAM);
36 return PKG_INVALID_PARAM;
37 }
38 size_t signatureSize = 0;
39 std::vector<uint8_t> signature;
40 uint16_t commentTotalLenAll = 0;
41 if (GetSignature(pkgStream, signatureSize, signature, commentTotalLenAll) != PKG_SUCCESS) {
42 PKG_LOGE("get package signature fail!");
43 UPDATER_LAST_WORD(PKG_INVALID_SIGNATURE);
44 return PKG_INVALID_SIGNATURE;
45 }
46
47 std::vector<uint8_t> hash;
48 int32_t ret = Pkcs7verify(signature, hash);
49 if (ret != PKG_SUCCESS) {
50 PKG_LOGE("pkcs7 verify fail!");
51 UPDATER_LAST_WORD(ret);
52 return ret;
53 }
54 size_t srcDataLen = pkgStream->GetFileLength() - commentTotalLenAll - 2;
55
56 ret = HashCheck(pkgStream, srcDataLen, hash);
57 if (ret != PKG_SUCCESS) {
58 srcDataLen = pkgStream->GetFileLength() - signatureSize - ZIP_EOCD_FIXED_PART_LEN;
59 ret = HashCheck(pkgStream, srcDataLen, hash);
60 }
61 return ret;
62 }
63
GetSignature(const PkgStreamPtr pkgStream,size_t & signatureSize,std::vector<uint8_t> & signature,uint16_t & commentTotalLenAll) const64 int32_t PkgVerifyUtil::GetSignature(const PkgStreamPtr pkgStream, size_t &signatureSize,
65 std::vector<uint8_t> &signature, uint16_t &commentTotalLenAll) const
66 {
67 size_t signatureStart = 0;
68 int32_t ret = ParsePackage(pkgStream, signatureStart, signatureSize, commentTotalLenAll);
69 if (ret != PKG_SUCCESS || signatureSize < PKG_FOOTER_SIZE) {
70 PKG_LOGE("Parse package failed.");
71 UPDATER_LAST_WORD(-1);
72 return -1;
73 }
74
75 size_t signDataLen = signatureSize - PKG_FOOTER_SIZE;
76 PkgBuffer signData(signDataLen);
77 size_t readLen = 0;
78 ret = pkgStream->Read(signData, signatureStart, signDataLen, readLen);
79 if (ret != PKG_SUCCESS) {
80 PKG_LOGE("read signature failed %s", pkgStream->GetFileName().c_str());
81 UPDATER_LAST_WORD(ret);
82 return ret;
83 }
84 signature.assign(signData.buffer, signData.buffer + readLen);
85
86 size_t fileLen = pkgStream->GetFileLength();
87 if (fileLen < (signatureSize + ZIP_EOCD_FIXED_PART_LEN)) {
88 PKG_LOGE("Invalid fileLen[%zu] and signature size[%zu]", fileLen, signatureSize);
89 UPDATER_LAST_WORD(PKG_INVALID_PARAM, fileLen, signatureSize);
90 return PKG_INVALID_PARAM;
91 }
92
93 return PKG_SUCCESS;
94 }
95
ParsePackage(const PkgStreamPtr pkgStream,size_t & signatureStart,size_t & signatureSize,uint16_t & commentTotalLenAll) const96 int32_t PkgVerifyUtil::ParsePackage(const PkgStreamPtr pkgStream, size_t &signatureStart,
97 size_t &signatureSize, uint16_t &commentTotalLenAll) const
98 {
99 ZipPkgParse zipParse;
100 PkgSignComment pkgSignComment {};
101 int32_t ret = zipParse.ParseZipPkg(pkgStream, pkgSignComment);
102 if (ret != PKG_SUCCESS) {
103 PKG_LOGE("Parse zip package signature failed.");
104 UPDATER_LAST_WORD(ret);
105 return ret;
106 }
107 signatureStart = pkgStream->GetFileLength() - pkgSignComment.signCommentAppendLen;
108 signatureSize = pkgSignComment.signCommentAppendLen;
109 commentTotalLenAll = pkgSignComment.signCommentTotalLen;
110
111 return PKG_SUCCESS;
112 }
113
Pkcs7verify(std::vector<uint8_t> & signature,std::vector<uint8_t> & hash) const114 int32_t PkgVerifyUtil::Pkcs7verify(std::vector<uint8_t> &signature, std::vector<uint8_t> &hash) const
115 {
116 Pkcs7SignedData pkcs7;
117
118 return pkcs7.GetHashFromSignBlock(signature.data(), signature.size(), hash);
119 }
120
HashCheck(const PkgStreamPtr srcData,const size_t dataLen,const std::vector<uint8_t> & hash) const121 int32_t PkgVerifyUtil::HashCheck(const PkgStreamPtr srcData, const size_t dataLen,
122 const std::vector<uint8_t> &hash) const
123 {
124 Updater::UPDATER_INIT_RECORD;
125 if (srcData == nullptr || dataLen == 0) {
126 UPDATER_LAST_WORD(PKG_INVALID_PARAM);
127 return PKG_INVALID_PARAM;
128 }
129
130 size_t digestLen = hash.size();
131 if (digestLen != PKG_HASH_CONTENT_LEN) {
132 PKG_LOGE("calc pkg sha256 digest failed.");
133 UPDATER_LAST_WORD(PKG_INVALID_PARAM);
134 return PKG_INVALID_PARAM;
135 }
136 std::vector<uint8_t> sourceDigest(digestLen);
137 int32_t ret = CalcSha256Digest(srcData, dataLen, sourceDigest);
138 if (ret != PKG_SUCCESS) {
139 PKG_LOGE("calc pkg sha256 digest failed.");
140 UPDATER_LAST_WORD(ret);
141 return ret;
142 }
143
144 if (memcmp(hash.data(), sourceDigest.data(), digestLen) != EOK) {
145 PKG_LOGE("Failed to memcmp data.");
146 UPDATER_LAST_WORD(PKG_INVALID_DIGEST);
147 return PKG_INVALID_DIGEST;
148 }
149
150 return PKG_SUCCESS;
151 }
152 } // namespace Hpackage
153