1fb299fa2Sopenharmony_ci/*
2fb299fa2Sopenharmony_ci * Copyright (c) 2023 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 "hash_data_verifier.h"
17fb299fa2Sopenharmony_ci#include "log/dump.h"
18fb299fa2Sopenharmony_ci#include "openssl_util.h"
19fb299fa2Sopenharmony_ci#include "package/pkg_manager.h"
20fb299fa2Sopenharmony_ci#include "pkcs7_signed_data.h"
21fb299fa2Sopenharmony_ci#include "rust/hash_signed_data.h"
22fb299fa2Sopenharmony_ci#include "updater/updater_const.h"
23fb299fa2Sopenharmony_ci#include "zip_pkg_parse.h"
24fb299fa2Sopenharmony_ci
25fb299fa2Sopenharmony_cinamespace Hpackage {
26fb299fa2Sopenharmony_ciusing namespace Updater;
27fb299fa2Sopenharmony_ciconstexpr static std::size_t MAX_SIG_SIZE = 1024;
28fb299fa2Sopenharmony_ciconstexpr const char *UPDATER_HASH_SIGNED_DATA = "hash_signed_data";
29fb299fa2Sopenharmony_ci
30fb299fa2Sopenharmony_ciHashDataVerifier::HashDataVerifier(PkgManager::PkgManagerPtr manager)
31fb299fa2Sopenharmony_ci    : manager_(manager), pkcs7_(std::make_unique<Pkcs7SignedData>()) {}
32fb299fa2Sopenharmony_ci
33fb299fa2Sopenharmony_ciHashDataVerifier::~HashDataVerifier()
34fb299fa2Sopenharmony_ci{
35fb299fa2Sopenharmony_ci    ReleaseHashSignedData(hsd_);
36fb299fa2Sopenharmony_ci}
37fb299fa2Sopenharmony_ci
38fb299fa2Sopenharmony_cibool HashDataVerifier::LoadHashDataAndPkcs7(const std::string &pkgPath)
39fb299fa2Sopenharmony_ci{
40fb299fa2Sopenharmony_ci    Updater::UPDATER_INIT_RECORD;
41fb299fa2Sopenharmony_ci    if (pkgPath == UPDATRE_SCRIPT_ZIP) {
42fb299fa2Sopenharmony_ci        isNeedVerify_ = false;
43fb299fa2Sopenharmony_ci        return true;
44fb299fa2Sopenharmony_ci    }
45fb299fa2Sopenharmony_ci    // only allow loading once
46fb299fa2Sopenharmony_ci    if (hsd_ != nullptr) {
47fb299fa2Sopenharmony_ci        PKG_LOGW("hash signed data has been loaded before");
48fb299fa2Sopenharmony_ci        return true;
49fb299fa2Sopenharmony_ci    }
50fb299fa2Sopenharmony_ci    if (manager_ == nullptr) {
51fb299fa2Sopenharmony_ci        PKG_LOGE("pkg manager is null");
52fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(false);
53fb299fa2Sopenharmony_ci        return false;
54fb299fa2Sopenharmony_ci    }
55fb299fa2Sopenharmony_ci    // load pkcs7 from package
56fb299fa2Sopenharmony_ci    if (!LoadPkcs7FromPackage(pkgPath)) {
57fb299fa2Sopenharmony_ci        PKG_LOGE("load pkcs7 from %s failed", pkgPath.c_str());
58fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_FILE, pkgPath);
59fb299fa2Sopenharmony_ci        return false;
60fb299fa2Sopenharmony_ci    }
61fb299fa2Sopenharmony_ci    if (!LoadHashDataFromPackage()) {
62fb299fa2Sopenharmony_ci        PKG_LOGE("load pkcs7 from %s failed", pkgPath.c_str());
63fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_FILE, pkgPath);
64fb299fa2Sopenharmony_ci        return false;
65fb299fa2Sopenharmony_ci    }
66fb299fa2Sopenharmony_ci    return true;
67fb299fa2Sopenharmony_ci}
68fb299fa2Sopenharmony_ci
69fb299fa2Sopenharmony_cibool HashDataVerifier::LoadHashDataFromPackage(const std::string &buffer)
70fb299fa2Sopenharmony_ci{
71fb299fa2Sopenharmony_ci    if (buffer.length() == 0) {
72fb299fa2Sopenharmony_ci        PKG_LOGE("buffer is empty");
73fb299fa2Sopenharmony_ci        return false;
74fb299fa2Sopenharmony_ci    }
75fb299fa2Sopenharmony_ci    hsd_ = LoadHashSignedData(reinterpret_cast<const char *>(buffer.data()));
76fb299fa2Sopenharmony_ci    return true;
77fb299fa2Sopenharmony_ci}
78fb299fa2Sopenharmony_ci
79fb299fa2Sopenharmony_cibool HashDataVerifier::LoadHashDataFromPackage(void)
80fb299fa2Sopenharmony_ci{
81fb299fa2Sopenharmony_ci    Updater::UPDATER_INIT_RECORD;
82fb299fa2Sopenharmony_ci    PkgManager::StreamPtr outStream = nullptr;
83fb299fa2Sopenharmony_ci    auto info = manager_->GetFileInfo(UPDATER_HASH_SIGNED_DATA);
84fb299fa2Sopenharmony_ci    if (info == nullptr || info->unpackedSize == 0) {
85fb299fa2Sopenharmony_ci        PKG_LOGE("hash signed data not find in pkg manager");
86fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(false);
87fb299fa2Sopenharmony_ci        return false;
88fb299fa2Sopenharmony_ci    }
89fb299fa2Sopenharmony_ci    // 1 more byte bigger than unpacked size to ensure a ending '\0' in buffer
90fb299fa2Sopenharmony_ci    PkgBuffer buffer {info->unpackedSize + 1};
91fb299fa2Sopenharmony_ci    int32_t ret = manager_->CreatePkgStream(outStream, "", buffer);
92fb299fa2Sopenharmony_ci    if (ret != PKG_SUCCESS) {
93fb299fa2Sopenharmony_ci        PKG_LOGE("create stream fail");
94fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(false);
95fb299fa2Sopenharmony_ci        return false;
96fb299fa2Sopenharmony_ci    }
97fb299fa2Sopenharmony_ci    ret = manager_->ExtractFile(UPDATER_HASH_SIGNED_DATA, outStream);
98fb299fa2Sopenharmony_ci    if (ret != PKG_SUCCESS) {
99fb299fa2Sopenharmony_ci        manager_->ClosePkgStream(outStream);
100fb299fa2Sopenharmony_ci        PKG_LOGE("extract file failed");
101fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(false);
102fb299fa2Sopenharmony_ci        return false;
103fb299fa2Sopenharmony_ci    }
104fb299fa2Sopenharmony_ci    hsd_ = LoadHashSignedData(reinterpret_cast<const char *>(buffer.data.data()));
105fb299fa2Sopenharmony_ci    manager_->ClosePkgStream(outStream);
106fb299fa2Sopenharmony_ci    if (hsd_ == nullptr) {
107fb299fa2Sopenharmony_ci        PKG_LOGE("load hash signed data failed");
108fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(false);
109fb299fa2Sopenharmony_ci        return false;
110fb299fa2Sopenharmony_ci    }
111fb299fa2Sopenharmony_ci    return true;
112fb299fa2Sopenharmony_ci}
113fb299fa2Sopenharmony_ci
114fb299fa2Sopenharmony_cibool HashDataVerifier::LoadPkcs7FromPackage(const std::string &pkgPath)
115fb299fa2Sopenharmony_ci{
116fb299fa2Sopenharmony_ci    PkgManager::StreamPtr pkgStream = nullptr;
117fb299fa2Sopenharmony_ci    int32_t ret = manager_->CreatePkgStream(pkgStream, pkgPath, 0, PkgStream::PkgStreamType_Read);
118fb299fa2Sopenharmony_ci    if (ret != PKG_SUCCESS) {
119fb299fa2Sopenharmony_ci        PKG_LOGE("CreatePackage fail %s", pkgPath.c_str());
120fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_FILE, pkgPath);
121fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(false);
122fb299fa2Sopenharmony_ci        return false;
123fb299fa2Sopenharmony_ci    }
124fb299fa2Sopenharmony_ci
125fb299fa2Sopenharmony_ci    PkgVerifyUtil verifyUtil {};
126fb299fa2Sopenharmony_ci    size_t signatureSize = 0;
127fb299fa2Sopenharmony_ci    std::vector<uint8_t> signature {};
128fb299fa2Sopenharmony_ci    uint16_t commentTotalLenAll = 0;
129fb299fa2Sopenharmony_ci    ret = verifyUtil.GetSignature(PkgStreamImpl::ConvertPkgStream(pkgStream),
130fb299fa2Sopenharmony_ci        signatureSize, signature, commentTotalLenAll);
131fb299fa2Sopenharmony_ci    manager_->ClosePkgStream(pkgStream);
132fb299fa2Sopenharmony_ci    if (ret != PKG_SUCCESS) {
133fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(ret);
134fb299fa2Sopenharmony_ci        return false;
135fb299fa2Sopenharmony_ci    }
136fb299fa2Sopenharmony_ci    return pkcs7_ != nullptr && pkcs7_->ParsePkcs7Data(signature.data(), signature.size()) == 0;
137fb299fa2Sopenharmony_ci}
138fb299fa2Sopenharmony_ci
139fb299fa2Sopenharmony_cibool HashDataVerifier::VerifyHashData(const std::string &preName,
140fb299fa2Sopenharmony_ci    const std::string &fileName, PkgManager::StreamPtr stream) const
141fb299fa2Sopenharmony_ci{
142fb299fa2Sopenharmony_ci    if (!isNeedVerify_) {
143fb299fa2Sopenharmony_ci        return true;
144fb299fa2Sopenharmony_ci    }
145fb299fa2Sopenharmony_ci    Updater::UPDATER_INIT_RECORD;
146fb299fa2Sopenharmony_ci    if (stream == nullptr) {
147fb299fa2Sopenharmony_ci        PKG_LOGE("stream is null");
148fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(false);
149fb299fa2Sopenharmony_ci        return false;
150fb299fa2Sopenharmony_ci    }
151fb299fa2Sopenharmony_ci
152fb299fa2Sopenharmony_ci    // get hash from stream
153fb299fa2Sopenharmony_ci    std::vector<uint8_t> hash {};
154fb299fa2Sopenharmony_ci    int32_t ret = CalcSha256Digest(PkgStreamImpl::ConvertPkgStream(stream), stream->GetFileLength(), hash);
155fb299fa2Sopenharmony_ci    if (ret != 0) {
156fb299fa2Sopenharmony_ci        PKG_LOGE("cal digest for pkg stream");
157fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(false, fileName);
158fb299fa2Sopenharmony_ci        return false;
159fb299fa2Sopenharmony_ci    }
160fb299fa2Sopenharmony_ci
161fb299fa2Sopenharmony_ci    // get sig from hash data
162fb299fa2Sopenharmony_ci    std::string name = preName + fileName;
163fb299fa2Sopenharmony_ci    std::vector<uint8_t> sig(MAX_SIG_SIZE, 0);
164fb299fa2Sopenharmony_ci    auto sigLen = GetSigFromHashData(hsd_, sig.data(), sig.size(), name.c_str());
165fb299fa2Sopenharmony_ci    if (sigLen == 0 || sig.size() < sigLen) {
166fb299fa2Sopenharmony_ci        PKG_LOGE("get sig for %s failed", name.c_str());
167fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_SIGNATURE, fileName, sigLen);
168fb299fa2Sopenharmony_ci        return false;
169fb299fa2Sopenharmony_ci    }
170fb299fa2Sopenharmony_ci    sig.resize(sigLen);
171fb299fa2Sopenharmony_ci
172fb299fa2Sopenharmony_ci    // then using cert from pkcs7 to verify hash data
173fb299fa2Sopenharmony_ci    if (pkcs7_ == nullptr || pkcs7_->Verify(hash, sig, false) != 0) {
174fb299fa2Sopenharmony_ci        PKG_LOGE("verify hash signed data for %s failed", fileName.c_str());
175fb299fa2Sopenharmony_ci        UPDATER_LAST_WORD(PKG_INVALID_SIGNATURE, fileName);
176fb299fa2Sopenharmony_ci        return false;
177fb299fa2Sopenharmony_ci    }
178fb299fa2Sopenharmony_ci    PKG_LOGI("verify hash signed data for %s successfully", fileName.c_str());
179fb299fa2Sopenharmony_ci    return true;
180fb299fa2Sopenharmony_ci}
181fb299fa2Sopenharmony_ci} // namespace Hpackage
182