1fb299fa2Sopenharmony_ci/*
2fb299fa2Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd.
3fb299fa2Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4fb299fa2Sopenharmony_ci * you may not use this file except in compliance with the License.
5fb299fa2Sopenharmony_ci * You may obtain a copy of the License at
6fb299fa2Sopenharmony_ci *
7fb299fa2Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8fb299fa2Sopenharmony_ci *
9fb299fa2Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10fb299fa2Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11fb299fa2Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fb299fa2Sopenharmony_ci * See the License for the specific language governing permissions and
13fb299fa2Sopenharmony_ci * limitations under the License.
14fb299fa2Sopenharmony_ci */
15fb299fa2Sopenharmony_ci
16fb299fa2Sopenharmony_ci#include "pkg_verify_util.h"
17fb299fa2Sopenharmony_ci#include <unistd.h>
18fb299fa2Sopenharmony_ci#include "dump.h"
19fb299fa2Sopenharmony_ci#include "openssl_util.h"
20fb299fa2Sopenharmony_ci#include "pkcs7_signed_data.h"
21fb299fa2Sopenharmony_ci#include "pkg_algo_sign.h"
22fb299fa2Sopenharmony_ci#include "pkg_algorithm.h"
23fb299fa2Sopenharmony_ci#include "pkg_manager_impl.h"
24fb299fa2Sopenharmony_ci#include "pkg_utils.h"
25fb299fa2Sopenharmony_ci#include "securec.h"
26fb299fa2Sopenharmony_ci#include "zip_pkg_parse.h"
27fb299fa2Sopenharmony_ci
28fb299fa2Sopenharmony_cinamespace Hpackage {
29fb299fa2Sopenharmony_cinamespace {
30fb299fa2Sopenharmony_ciconstexpr uint32_t ZIP_EOCD_FIXED_PART_LEN = 22;
31fb299fa2Sopenharmony_ciconstexpr uint32_t PKG_FOOTER_SIZE = 6;
32fb299fa2Sopenharmony_ciconstexpr uint32_t PKG_HASH_CONTENT_LEN = SHA256_DIGEST_LENGTH;
33fb299fa2Sopenharmony_ci}
34fb299fa2Sopenharmony_ci
35fb299fa2Sopenharmony_ciint32_t PkgVerifyUtil::VerifySourceDigest(std::vector<uint8_t> &signature, std::vector<uint8_t> &sourceDigest,
36fb299fa2Sopenharmony_ci    const std::string & keyPath) const
37fb299fa2Sopenharmony_ci{
38fb299fa2Sopenharmony_ci    std::vector<std::vector<uint8_t>> sigs;
39fb299fa2Sopenharmony_ci    Pkcs7SignedData pkcs7;
40fb299fa2Sopenharmony_ci    SignAlgorithm::SignAlgorithmPtr signAlgorithm = PkgAlgorithmFactory::GetVerifyAlgorithm(
41fb299fa2Sopenharmony_ci        keyPath, PKG_DIGEST_TYPE_SHA256);
42fb299fa2Sopenharmony_ci    int32_t ret = pkcs7.ReadSig(signature.data(), signature.size(), sigs);
43fb299fa2Sopenharmony_ci    if (ret != PKCS7_SUCCESS) {
44fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD("pkcs7", ret);
45fb299fa2Sopenharmony_ci        return ret;
46fb299fa2Sopenharmony_ci    }
47fb299fa2Sopenharmony_ci    for (auto &sig : sigs) {
48fb299fa2Sopenharmony_ci        if (signAlgorithm->VerifyDigest(sourceDigest, sig) == 0) {
49fb299fa2Sopenharmony_ci            return PKG_SUCCESS;
50fb299fa2Sopenharmony_ci        }
51fb299fa2Sopenharmony_ci    }
52fb299fa2Sopenharmony_ci    return PKG_VERIFY_FAIL;
53fb299fa2Sopenharmony_ci}
54fb299fa2Sopenharmony_ci
55fb299fa2Sopenharmony_ciint32_t PkgVerifyUtil::VerifyAccPackageSign(const PkgStreamPtr pkgStream, const std::string &keyPath) const
56fb299fa2Sopenharmony_ci{
57fb299fa2Sopenharmony_ci    if (pkgStream == nullptr) {
58fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_PARAM);
59fb299fa2Sopenharmony_ci        return PKG_INVALID_PARAM;
60fb299fa2Sopenharmony_ci    }
61fb299fa2Sopenharmony_ci    size_t signatureSize = 0;
62fb299fa2Sopenharmony_ci    std::vector<uint8_t> signature;
63fb299fa2Sopenharmony_ci    uint16_t commentTotalLenAll = 0;
64fb299fa2Sopenharmony_ci    if (GetSignature(pkgStream, signatureSize, signature, commentTotalLenAll) != PKG_SUCCESS) {
65fb299fa2Sopenharmony_ci        PKG_LOGE("get package signature fail!");
66fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_SIGNATURE);
67fb299fa2Sopenharmony_ci        return PKG_INVALID_SIGNATURE;
68fb299fa2Sopenharmony_ci    }
69fb299fa2Sopenharmony_ci    size_t srcDataLen = pkgStream->GetFileLength() - commentTotalLenAll -2;
70fb299fa2Sopenharmony_ci    size_t readLen = 0;
71fb299fa2Sopenharmony_ci    std::vector<uint8_t> sourceDigest;
72fb299fa2Sopenharmony_ci    PkgBuffer digest(srcDataLen);
73fb299fa2Sopenharmony_ci    pkgStream->Read(digest, 0, srcDataLen, readLen);
74fb299fa2Sopenharmony_ci    sourceDigest.assign(digest.buffer, digest.buffer + readLen);
75fb299fa2Sopenharmony_ci    return VerifySourceDigest(signature, sourceDigest, keyPath);
76fb299fa2Sopenharmony_ci}
77fb299fa2Sopenharmony_ci
78fb299fa2Sopenharmony_ciint32_t PkgVerifyUtil::VerifySign(std::vector<uint8_t> &signData, std::vector<uint8_t> &digest) const
79fb299fa2Sopenharmony_ci{
80fb299fa2Sopenharmony_ci    std::vector<uint8_t> hash;
81fb299fa2Sopenharmony_ci    int32_t ret = Pkcs7verify(signData, hash);
82fb299fa2Sopenharmony_ci    if (ret != PKG_SUCCESS) {
83fb299fa2Sopenharmony_ci        PKG_LOGE("pkcs7 verify fail!");
84fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(ret);
85fb299fa2Sopenharmony_ci        return ret;
86fb299fa2Sopenharmony_ci    }
87fb299fa2Sopenharmony_ci    size_t hashLen = hash.size();
88fb299fa2Sopenharmony_ci    if ((hashLen != digest.size()) || memcmp(hash.data(), digest.data(), hashLen) != EOK) {
89fb299fa2Sopenharmony_ci        PKG_LOGE("Failed to memcmp data.");
90fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_DIGEST);
91fb299fa2Sopenharmony_ci        return PKG_INVALID_DIGEST;
92fb299fa2Sopenharmony_ci    }
93fb299fa2Sopenharmony_ci    return PKG_SUCCESS;
94fb299fa2Sopenharmony_ci}
95fb299fa2Sopenharmony_ci
96fb299fa2Sopenharmony_ciint32_t PkgVerifyUtil::VerifyPackageSign(const PkgStreamPtr pkgStream) const
97fb299fa2Sopenharmony_ci{
98fb299fa2Sopenharmony_ci    if (pkgStream == nullptr) {
99fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_PARAM);
100fb299fa2Sopenharmony_ci        return PKG_INVALID_PARAM;
101fb299fa2Sopenharmony_ci    }
102fb299fa2Sopenharmony_ci    size_t signatureSize = 0;
103fb299fa2Sopenharmony_ci    std::vector<uint8_t> signature;
104fb299fa2Sopenharmony_ci    uint16_t commentTotalLenAll = 0;
105fb299fa2Sopenharmony_ci    if (GetSignature(pkgStream, signatureSize, signature, commentTotalLenAll) != PKG_SUCCESS) {
106fb299fa2Sopenharmony_ci        PKG_LOGE("get package signature fail!");
107fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_SIGNATURE);
108fb299fa2Sopenharmony_ci        return PKG_INVALID_SIGNATURE;
109fb299fa2Sopenharmony_ci    }
110fb299fa2Sopenharmony_ci
111fb299fa2Sopenharmony_ci    std::vector<uint8_t> hash;
112fb299fa2Sopenharmony_ci    int32_t ret = Pkcs7verify(signature, hash);
113fb299fa2Sopenharmony_ci    if (ret != PKG_SUCCESS) {
114fb299fa2Sopenharmony_ci        PKG_LOGE("pkcs7 verify fail!");
115fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(ret);
116fb299fa2Sopenharmony_ci        return ret;
117fb299fa2Sopenharmony_ci    }
118fb299fa2Sopenharmony_ci    size_t srcDataLen = pkgStream->GetFileLength() - commentTotalLenAll - 2;
119fb299fa2Sopenharmony_ci
120fb299fa2Sopenharmony_ci    ret =  HashCheck(pkgStream, srcDataLen, hash);
121fb299fa2Sopenharmony_ci    if (ret != PKG_SUCCESS) {
122fb299fa2Sopenharmony_ci        srcDataLen = pkgStream->GetFileLength() - signatureSize - ZIP_EOCD_FIXED_PART_LEN;
123fb299fa2Sopenharmony_ci        ret = HashCheck(pkgStream, srcDataLen, hash);
124fb299fa2Sopenharmony_ci    }
125fb299fa2Sopenharmony_ci    PKG_LOGI("verify package signature %s", ret == PKG_SUCCESS ? "successfull" : "failed");
126fb299fa2Sopenharmony_ci    return ret;
127fb299fa2Sopenharmony_ci}
128fb299fa2Sopenharmony_ci
129fb299fa2Sopenharmony_ciint32_t PkgVerifyUtil::GetSignature(const PkgStreamPtr pkgStream, size_t &signatureSize,
130fb299fa2Sopenharmony_ci    std::vector<uint8_t> &signature, uint16_t &commentTotalLenAll) const
131fb299fa2Sopenharmony_ci{
132fb299fa2Sopenharmony_ci    size_t signatureStart = 0;
133fb299fa2Sopenharmony_ci    int32_t ret = ParsePackage(pkgStream, signatureStart, signatureSize, commentTotalLenAll);
134fb299fa2Sopenharmony_ci    if (ret != PKG_SUCCESS || signatureSize < PKG_FOOTER_SIZE) {
135fb299fa2Sopenharmony_ci        PKG_LOGE("Parse package failed.");
136fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(-1);
137fb299fa2Sopenharmony_ci        return -1;
138fb299fa2Sopenharmony_ci    }
139fb299fa2Sopenharmony_ci
140fb299fa2Sopenharmony_ci    size_t signDataLen = signatureSize - PKG_FOOTER_SIZE;
141fb299fa2Sopenharmony_ci    PkgBuffer signData(signDataLen);
142fb299fa2Sopenharmony_ci    size_t readLen = 0;
143fb299fa2Sopenharmony_ci    ret = pkgStream->Read(signData, signatureStart, signDataLen, readLen);
144fb299fa2Sopenharmony_ci    if (ret != PKG_SUCCESS) {
145fb299fa2Sopenharmony_ci        PKG_LOGE("read signature failed %s", pkgStream->GetFileName().c_str());
146fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(ret);
147fb299fa2Sopenharmony_ci        return ret;
148fb299fa2Sopenharmony_ci    }
149fb299fa2Sopenharmony_ci    signature.assign(signData.buffer, signData.buffer + readLen);
150fb299fa2Sopenharmony_ci
151fb299fa2Sopenharmony_ci    size_t fileLen = pkgStream->GetFileLength();
152fb299fa2Sopenharmony_ci    if (fileLen < (signatureSize + ZIP_EOCD_FIXED_PART_LEN)) {
153fb299fa2Sopenharmony_ci        PKG_LOGE("Invalid fileLen[%zu] and signature size[%zu]", fileLen, signatureSize);
154fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_PARAM, fileLen, signatureSize);
155fb299fa2Sopenharmony_ci        return PKG_INVALID_PARAM;
156fb299fa2Sopenharmony_ci    }
157fb299fa2Sopenharmony_ci
158fb299fa2Sopenharmony_ci    return PKG_SUCCESS;
159fb299fa2Sopenharmony_ci}
160fb299fa2Sopenharmony_ci
161fb299fa2Sopenharmony_ciint32_t PkgVerifyUtil::ParsePackage(const PkgStreamPtr pkgStream, size_t &signatureStart,
162fb299fa2Sopenharmony_ci    size_t &signatureSize, uint16_t &commentTotalLenAll) const
163fb299fa2Sopenharmony_ci{
164fb299fa2Sopenharmony_ci    ZipPkgParse zipParse;
165fb299fa2Sopenharmony_ci    PkgSignComment pkgSignComment {};
166fb299fa2Sopenharmony_ci    int32_t ret = zipParse.ParseZipPkg(pkgStream, pkgSignComment);
167fb299fa2Sopenharmony_ci    if (ret != PKG_SUCCESS) {
168fb299fa2Sopenharmony_ci        PKG_LOGE("Parse zip package signature failed.");
169fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(ret);
170fb299fa2Sopenharmony_ci        return ret;
171fb299fa2Sopenharmony_ci    }
172fb299fa2Sopenharmony_ci    signatureStart = pkgStream->GetFileLength() - pkgSignComment.signCommentAppendLen;
173fb299fa2Sopenharmony_ci    signatureSize = pkgSignComment.signCommentAppendLen;
174fb299fa2Sopenharmony_ci    commentTotalLenAll = pkgSignComment.signCommentTotalLen;
175fb299fa2Sopenharmony_ci
176fb299fa2Sopenharmony_ci    return PKG_SUCCESS;
177fb299fa2Sopenharmony_ci}
178fb299fa2Sopenharmony_ci
179fb299fa2Sopenharmony_ciint32_t PkgVerifyUtil::Pkcs7verify(std::vector<uint8_t> &signature, std::vector<uint8_t> &hash) const
180fb299fa2Sopenharmony_ci{
181fb299fa2Sopenharmony_ci    Pkcs7SignedData pkcs7;
182fb299fa2Sopenharmony_ci
183fb299fa2Sopenharmony_ci    return pkcs7.GetHashFromSignBlock(signature.data(), signature.size(), hash);
184fb299fa2Sopenharmony_ci}
185fb299fa2Sopenharmony_ci
186fb299fa2Sopenharmony_ciint32_t PkgVerifyUtil::HashCheck(const PkgStreamPtr srcData, const size_t dataLen,
187fb299fa2Sopenharmony_ci    const std::vector<uint8_t> &hash) const
188fb299fa2Sopenharmony_ci{
189fb299fa2Sopenharmony_ci    Updater::UPDATER_INIT_RECORD;
190fb299fa2Sopenharmony_ci    if (srcData == nullptr || dataLen == 0) {
191fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_PARAM);
192fb299fa2Sopenharmony_ci        return PKG_INVALID_PARAM;
193fb299fa2Sopenharmony_ci    }
194fb299fa2Sopenharmony_ci
195fb299fa2Sopenharmony_ci    size_t digestLen = hash.size();
196fb299fa2Sopenharmony_ci    if (digestLen != PKG_HASH_CONTENT_LEN) {
197fb299fa2Sopenharmony_ci        PKG_LOGE("calc pkg sha256 digest failed.");
198fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_PARAM);
199fb299fa2Sopenharmony_ci        return PKG_INVALID_PARAM;
200fb299fa2Sopenharmony_ci    }
201fb299fa2Sopenharmony_ci    std::vector<uint8_t> sourceDigest(digestLen);
202fb299fa2Sopenharmony_ci    int32_t ret = CalcSha256Digest(srcData, dataLen, sourceDigest);
203fb299fa2Sopenharmony_ci    if (ret != PKG_SUCCESS) {
204fb299fa2Sopenharmony_ci        PKG_LOGE("calc pkg sha256 digest failed.");
205fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(ret);
206fb299fa2Sopenharmony_ci        return ret;
207fb299fa2Sopenharmony_ci    }
208fb299fa2Sopenharmony_ci
209fb299fa2Sopenharmony_ci    if (memcmp(hash.data(), sourceDigest.data(), digestLen) != EOK) {
210fb299fa2Sopenharmony_ci        PKG_LOGW("Failed to memcmp data.");
211fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_DIGEST);
212fb299fa2Sopenharmony_ci        return PKG_INVALID_DIGEST;
213fb299fa2Sopenharmony_ci    }
214fb299fa2Sopenharmony_ci
215fb299fa2Sopenharmony_ci    return PKG_SUCCESS;
216fb299fa2Sopenharmony_ci}
217fb299fa2Sopenharmony_ci} // namespace Hpackage
218