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