154aa6d63Sopenharmony_ci/*
254aa6d63Sopenharmony_ci * Copyright (c) 2024-2024 Huawei Device Co., Ltd.
354aa6d63Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
454aa6d63Sopenharmony_ci * you may not use this file except in compliance with the License.
554aa6d63Sopenharmony_ci * You may obtain a copy of the License at
654aa6d63Sopenharmony_ci *
754aa6d63Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
854aa6d63Sopenharmony_ci *
954aa6d63Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1054aa6d63Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1154aa6d63Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1254aa6d63Sopenharmony_ci * See the License for the specific language governing permissions and
1354aa6d63Sopenharmony_ci * limitations under the License.
1454aa6d63Sopenharmony_ci */
1554aa6d63Sopenharmony_ci#include <climits>
1654aa6d63Sopenharmony_ci#include <cstdlib>
1754aa6d63Sopenharmony_ci#include <regex>
1854aa6d63Sopenharmony_ci#include <unordered_map>
1954aa6d63Sopenharmony_ci#include <vector>
2054aa6d63Sopenharmony_ci#include <algorithm>
2154aa6d63Sopenharmony_ci
2254aa6d63Sopenharmony_ci#include "securec.h"
2354aa6d63Sopenharmony_ci#include "hap_signer_block_utils.h"
2454aa6d63Sopenharmony_ci#include "signature_info.h"
2554aa6d63Sopenharmony_ci#include "options.h"
2654aa6d63Sopenharmony_ci#include "openssl/pem.h"
2754aa6d63Sopenharmony_ci#include "pkcs7_data.h"
2854aa6d63Sopenharmony_ci#include "hap_utils.h"
2954aa6d63Sopenharmony_ci#include "string_utils.h"
3054aa6d63Sopenharmony_ci#include "verify_code_signature.h"
3154aa6d63Sopenharmony_ci#include "param_constants.h"
3254aa6d63Sopenharmony_ci#include "file_utils.h"
3354aa6d63Sopenharmony_ci#include "nlohmann/json.hpp"
3454aa6d63Sopenharmony_ci#include "verify_hap.h"
3554aa6d63Sopenharmony_ci
3654aa6d63Sopenharmony_ciusing namespace nlohmann;
3754aa6d63Sopenharmony_cinamespace OHOS {
3854aa6d63Sopenharmony_cinamespace SignatureTools {
3954aa6d63Sopenharmony_ciconst int32_t VerifyHap::HEX_PRINT_LENGTH = 3;
4054aa6d63Sopenharmony_ciconst int32_t VerifyHap::DIGEST_BLOCK_LEN_OFFSET = 8;
4154aa6d63Sopenharmony_ciconst int32_t VerifyHap::DIGEST_ALGORITHM_OFFSET = 12;
4254aa6d63Sopenharmony_ciconst int32_t VerifyHap::DIGEST_LEN_OFFSET = 16;
4354aa6d63Sopenharmony_ciconst int32_t VerifyHap::DIGEST_OFFSET_IN_CONTENT = 20;
4454aa6d63Sopenharmony_ciconst std::string VerifyHap::HAP_APP_PATTERN = "[^]*.hap$";
4554aa6d63Sopenharmony_ciconst std::string VerifyHap::HQF_APP_PATTERN = "[^]*.hqf$";
4654aa6d63Sopenharmony_ciconst std::string VerifyHap::HSP_APP_PATTERN = "[^]*.hsp$";
4754aa6d63Sopenharmony_ciconst std::string VerifyHap::APP_APP_PATTERN = "[^]*.app$";
4854aa6d63Sopenharmony_cistatic constexpr int ZIP_HEAD_OF_SUBSIGNING_BLOCK_LENGTH = 12;
4954aa6d63Sopenharmony_ci
5054aa6d63Sopenharmony_ciVerifyHap::VerifyHap() : isPrintCert(true)
5154aa6d63Sopenharmony_ci{
5254aa6d63Sopenharmony_ci}
5354aa6d63Sopenharmony_ci
5454aa6d63Sopenharmony_ciVerifyHap::VerifyHap(bool printCert)
5554aa6d63Sopenharmony_ci{
5654aa6d63Sopenharmony_ci    isPrintCert = printCert;
5754aa6d63Sopenharmony_ci}
5854aa6d63Sopenharmony_ci
5954aa6d63Sopenharmony_civoid VerifyHap::setIsPrintCert(bool printCert)
6054aa6d63Sopenharmony_ci{
6154aa6d63Sopenharmony_ci    isPrintCert = printCert;
6254aa6d63Sopenharmony_ci}
6354aa6d63Sopenharmony_ci
6454aa6d63Sopenharmony_cibool VerifyHap::HapOutPutPkcs7(PKCS7* p7, const std::string& outPutPath)
6554aa6d63Sopenharmony_ci{
6654aa6d63Sopenharmony_ci    std::string p7bContent = StringUtils::Pkcs7ToString(p7);
6754aa6d63Sopenharmony_ci    if (p7bContent.empty()) {
6854aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("p7b to string failed!\n");
6954aa6d63Sopenharmony_ci        return false;
7054aa6d63Sopenharmony_ci    }
7154aa6d63Sopenharmony_ci    if (FileUtils::Write(p7bContent, outPutPath) < 0) {
7254aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("p7b write to file falied!\n");
7354aa6d63Sopenharmony_ci        return false;
7454aa6d63Sopenharmony_ci    }
7554aa6d63Sopenharmony_ci    return true;
7654aa6d63Sopenharmony_ci}
7754aa6d63Sopenharmony_ci
7854aa6d63Sopenharmony_cibool VerifyHap::outputOptionalBlocks(const std::string& outputProfileFile, const std::string& outputProofFile,
7954aa6d63Sopenharmony_ci                                     const std::string& outputPropertyFile,
8054aa6d63Sopenharmony_ci                                     const std::vector<OptionalBlock>& optionBlocks)
8154aa6d63Sopenharmony_ci{
8254aa6d63Sopenharmony_ci    for (auto& optionBlock : optionBlocks) {
8354aa6d63Sopenharmony_ci        if (optionBlock.optionalType == HapUtils::HAP_PROFILE_BLOCK_ID) {
8454aa6d63Sopenharmony_ci            if (!writeOptionalBytesToFile(optionBlock, outputProfileFile)) {
8554aa6d63Sopenharmony_ci                return false;
8654aa6d63Sopenharmony_ci            }
8754aa6d63Sopenharmony_ci        } else if (optionBlock.optionalType == HapUtils::HAP_PROPERTY_BLOCK_ID) {
8854aa6d63Sopenharmony_ci            if (!writeOptionalBytesToFile(optionBlock, outputPropertyFile)) {
8954aa6d63Sopenharmony_ci                return false;
9054aa6d63Sopenharmony_ci            }
9154aa6d63Sopenharmony_ci        } else if (optionBlock.optionalType == HapUtils::HAP_PROOF_OF_ROTATION_BLOCK_ID) {
9254aa6d63Sopenharmony_ci            if (!writeOptionalBytesToFile(optionBlock, outputProofFile)) {
9354aa6d63Sopenharmony_ci                return false;
9454aa6d63Sopenharmony_ci            }
9554aa6d63Sopenharmony_ci        } else {
9654aa6d63Sopenharmony_ci            SIGNATURE_TOOLS_LOGE("Unsupported Block Id: %d", optionBlock.optionalType);
9754aa6d63Sopenharmony_ci            return false;
9854aa6d63Sopenharmony_ci        }
9954aa6d63Sopenharmony_ci    }
10054aa6d63Sopenharmony_ci    return true;
10154aa6d63Sopenharmony_ci}
10254aa6d63Sopenharmony_cibool VerifyHap::writeOptionalBytesToFile(const OptionalBlock& optionalBlock, const std::string& path)
10354aa6d63Sopenharmony_ci{
10454aa6d63Sopenharmony_ci    if (path.empty()) {
10554aa6d63Sopenharmony_ci        return true;
10654aa6d63Sopenharmony_ci    }
10754aa6d63Sopenharmony_ci    std::string optionBlockString(optionalBlock.optionalBlockValue.GetBufferPtr(),
10854aa6d63Sopenharmony_ci                          optionalBlock.optionalBlockValue.GetCapacity());
10954aa6d63Sopenharmony_ci    if (FileUtils::Write(optionBlockString, path) < 0) {
11054aa6d63Sopenharmony_ci        PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "write optional bytes to file:" + path + " falied!");
11154aa6d63Sopenharmony_ci        return false;
11254aa6d63Sopenharmony_ci    }
11354aa6d63Sopenharmony_ci    return true;
11454aa6d63Sopenharmony_ci}
11554aa6d63Sopenharmony_ci
11654aa6d63Sopenharmony_cibool VerifyHap::HapOutPutCertChain(std::vector<X509*>& certs, const std::string& outPutPath)
11754aa6d63Sopenharmony_ci{
11854aa6d63Sopenharmony_ci    if (isPrintCert) {
11954aa6d63Sopenharmony_ci        if (!PrintCertChainToCmd(certs)) {
12054aa6d63Sopenharmony_ci            SIGNATURE_TOOLS_LOGE("print cert chain to cmd failed\n");
12154aa6d63Sopenharmony_ci            return false;
12254aa6d63Sopenharmony_ci        }
12354aa6d63Sopenharmony_ci    }
12454aa6d63Sopenharmony_ci    VerifyHapOpensslUtils::GetOpensslErrorMessage();
12554aa6d63Sopenharmony_ci    SIGNATURE_TOOLS_LOGD("outPutPath = %s", outPutPath.c_str());
12654aa6d63Sopenharmony_ci    std::vector<std::string> certStr;
12754aa6d63Sopenharmony_ci    for (auto& cert : certs) {
12854aa6d63Sopenharmony_ci        certStr.emplace_back(StringUtils::SubjectToString(cert));
12954aa6d63Sopenharmony_ci        certStr.emplace_back(StringUtils::x509CertToString(cert));
13054aa6d63Sopenharmony_ci    }
13154aa6d63Sopenharmony_ci    std::string outPutCertChainContent;
13254aa6d63Sopenharmony_ci    for (auto& certstr : certStr) {
13354aa6d63Sopenharmony_ci        outPutCertChainContent += certstr;
13454aa6d63Sopenharmony_ci    }
13554aa6d63Sopenharmony_ci    if (FileUtils::Write(outPutCertChainContent, outPutPath) < 0) {
13654aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("certChain write to file falied!\n");
13754aa6d63Sopenharmony_ci        return false;
13854aa6d63Sopenharmony_ci    }
13954aa6d63Sopenharmony_ci    return true;
14054aa6d63Sopenharmony_ci}
14154aa6d63Sopenharmony_ci
14254aa6d63Sopenharmony_ciint32_t VerifyHap::Verify(const std::string& filePath, Options* options)
14354aa6d63Sopenharmony_ci{
14454aa6d63Sopenharmony_ci    SIGNATURE_TOOLS_LOGD("Start Verify");
14554aa6d63Sopenharmony_ci    std::string standardFilePath;
14654aa6d63Sopenharmony_ci    if (!CheckFilePath(filePath, standardFilePath)) {
14754aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("Check file path%s failed", filePath.c_str());
14854aa6d63Sopenharmony_ci        return IO_ERROR;
14954aa6d63Sopenharmony_ci    }
15054aa6d63Sopenharmony_ci    RandomAccessFile hapFile;
15154aa6d63Sopenharmony_ci    if (!hapFile.Init(standardFilePath)) {
15254aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("%s init failed", standardFilePath.c_str());
15354aa6d63Sopenharmony_ci        return ZIP_ERROR;
15454aa6d63Sopenharmony_ci    }
15554aa6d63Sopenharmony_ci    int32_t resultCode = Verify(hapFile, options, filePath);
15654aa6d63Sopenharmony_ci    if (resultCode != RET_OK) {
15754aa6d63Sopenharmony_ci        PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, standardFilePath + " verify failed");
15854aa6d63Sopenharmony_ci    }
15954aa6d63Sopenharmony_ci    return resultCode;
16054aa6d63Sopenharmony_ci}
16154aa6d63Sopenharmony_ci
16254aa6d63Sopenharmony_cibool VerifyHap::CheckFilePath(const std::string& filePath, std::string& standardFilePath)
16354aa6d63Sopenharmony_ci{
16454aa6d63Sopenharmony_ci    char path[PATH_MAX] = { 0x00 };
16554aa6d63Sopenharmony_ci    if (filePath.size() > PATH_MAX || realpath(filePath.c_str(), path) == nullptr) {
16654aa6d63Sopenharmony_ci        PrintErrorNumberMsg("IO_ERROR", IO_ERROR,
16754aa6d63Sopenharmony_ci                            filePath + " does not exist or is over " + std::to_string(PATH_MAX) + " chars");
16854aa6d63Sopenharmony_ci        return false;
16954aa6d63Sopenharmony_ci    }
17054aa6d63Sopenharmony_ci    standardFilePath = std::string(path);
17154aa6d63Sopenharmony_ci    std::string standardFilePathTmp = std::string(path);
17254aa6d63Sopenharmony_ci    std::transform(standardFilePathTmp.begin(), standardFilePathTmp.end(), standardFilePathTmp.begin(),
17354aa6d63Sopenharmony_ci                   [](unsigned char c) { return std::tolower(c); });
17454aa6d63Sopenharmony_ci    bool ret = (!std::regex_match(standardFilePathTmp, std::regex(HAP_APP_PATTERN)) &&
17554aa6d63Sopenharmony_ci                !std::regex_match(standardFilePathTmp, std::regex(HSP_APP_PATTERN)) &&
17654aa6d63Sopenharmony_ci                !std::regex_match(standardFilePathTmp, std::regex(APP_APP_PATTERN)) &&
17754aa6d63Sopenharmony_ci                !std::regex_match(standardFilePathTmp, std::regex(HQF_APP_PATTERN)));
17854aa6d63Sopenharmony_ci    if (ret) {
17954aa6d63Sopenharmony_ci        PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR,
18054aa6d63Sopenharmony_ci                            "only support format is [hap, hqf, hsp, app]");
18154aa6d63Sopenharmony_ci        return false;
18254aa6d63Sopenharmony_ci    }
18354aa6d63Sopenharmony_ci    return true;
18454aa6d63Sopenharmony_ci}
18554aa6d63Sopenharmony_ci
18654aa6d63Sopenharmony_ciint32_t VerifyHap::Verify(RandomAccessFile& hapFile, Options* options, const std::string& filePath)
18754aa6d63Sopenharmony_ci{
18854aa6d63Sopenharmony_ci    SignatureInfo hapSignInfo;
18954aa6d63Sopenharmony_ci    if (!HapSignerBlockUtils::FindHapSignature(hapFile, hapSignInfo)) {
19054aa6d63Sopenharmony_ci        return ZIP_ERROR;
19154aa6d63Sopenharmony_ci    }
19254aa6d63Sopenharmony_ci
19354aa6d63Sopenharmony_ci    if (CheckCodeSign(filePath, hapSignInfo.optionBlocks) == false) {
19454aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("check coode sign failed\n");
19554aa6d63Sopenharmony_ci        return VERIFY_ERROR;
19654aa6d63Sopenharmony_ci    }
19754aa6d63Sopenharmony_ci
19854aa6d63Sopenharmony_ci    Pkcs7Context pkcs7Context;
19954aa6d63Sopenharmony_ci    if (!VerifyAppPkcs7(pkcs7Context, hapSignInfo.hapSignatureBlock)) {
20054aa6d63Sopenharmony_ci        return PARSE_ERROR;
20154aa6d63Sopenharmony_ci    }
20254aa6d63Sopenharmony_ci
20354aa6d63Sopenharmony_ci    if (!GetDigestAndAlgorithm(pkcs7Context)) {
20454aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("Get digest failed");
20554aa6d63Sopenharmony_ci        return PARSE_ERROR;
20654aa6d63Sopenharmony_ci    }
20754aa6d63Sopenharmony_ci
20854aa6d63Sopenharmony_ci    STACK_OF(X509_CRL)* x509Crl = nullptr;
20954aa6d63Sopenharmony_ci    if (!VerifyHapOpensslUtils::GetCrlStack(pkcs7Context.p7, x509Crl)) {
21054aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("Get Crl stack failed");
21154aa6d63Sopenharmony_ci        return PARSE_ERROR;
21254aa6d63Sopenharmony_ci    }
21354aa6d63Sopenharmony_ci
21454aa6d63Sopenharmony_ci    if (!VerifyCertOpensslUtils::VerifyCrl(pkcs7Context.certChain[0], x509Crl, pkcs7Context)) {
21554aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("Verify Crl stack failed");
21654aa6d63Sopenharmony_ci        return VERIFY_ERROR;
21754aa6d63Sopenharmony_ci    }
21854aa6d63Sopenharmony_ci
21954aa6d63Sopenharmony_ci    if (!HapSignerBlockUtils::VerifyHapIntegrity(pkcs7Context, hapFile, hapSignInfo)) {
22054aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("Verify Integrity failed");
22154aa6d63Sopenharmony_ci        return VERIFY_ERROR;
22254aa6d63Sopenharmony_ci    }
22354aa6d63Sopenharmony_ci    if (!HapOutPutCertChain(pkcs7Context.certChain[0],
22454aa6d63Sopenharmony_ci        options->GetString(Options::OUT_CERT_CHAIN))) {
22554aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("out put cert chain failed");
22654aa6d63Sopenharmony_ci        return IO_ERROR;
22754aa6d63Sopenharmony_ci    }
22854aa6d63Sopenharmony_ci
22954aa6d63Sopenharmony_ci    if (!outputOptionalBlocks(options->GetString(ParamConstants::PARAM_VERIFY_PROFILE_FILE),
23054aa6d63Sopenharmony_ci                              options->GetString(ParamConstants::PARAM_VERIFY_PROOF_FILE),
23154aa6d63Sopenharmony_ci                              options->GetString(ParamConstants::PARAM_VERIFY_PROPERTY_FILE),
23254aa6d63Sopenharmony_ci                              hapSignInfo.optionBlocks)) {
23354aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("output Optional Blocks failed");
23454aa6d63Sopenharmony_ci        return IO_ERROR;
23554aa6d63Sopenharmony_ci    }
23654aa6d63Sopenharmony_ci    return RET_OK;
23754aa6d63Sopenharmony_ci}
23854aa6d63Sopenharmony_ci
23954aa6d63Sopenharmony_cibool VerifyHap::CheckCodeSign(const std::string& hapFilePath,
24054aa6d63Sopenharmony_ci                              const std::vector<OptionalBlock>& optionalBlocks)const
24154aa6d63Sopenharmony_ci{
24254aa6d63Sopenharmony_ci    std::unordered_map<int, ByteBuffer> map;
24354aa6d63Sopenharmony_ci    for (const OptionalBlock& block : optionalBlocks) {
24454aa6d63Sopenharmony_ci        map.emplace(block.optionalType, block.optionalBlockValue);
24554aa6d63Sopenharmony_ci    }
24654aa6d63Sopenharmony_ci    bool codeSignFlag = map.find(HapUtils::HAP_PROPERTY_BLOCK_ID) != map.end() &&
24754aa6d63Sopenharmony_ci        map[HapUtils::HAP_PROPERTY_BLOCK_ID].GetCapacity() > 0;
24854aa6d63Sopenharmony_ci    if (codeSignFlag) {
24954aa6d63Sopenharmony_ci        ByteBuffer propertyBlockArray = map[HapUtils::HAP_PROPERTY_BLOCK_ID];
25054aa6d63Sopenharmony_ci        std::vector<std::string> fileNameArray = StringUtils::SplitString(hapFilePath, '.');
25154aa6d63Sopenharmony_ci        if (fileNameArray.size() < ParamConstants::FILE_NAME_MIN_LENGTH) {
25254aa6d63Sopenharmony_ci            PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "ZIP64 format not supported.");
25354aa6d63Sopenharmony_ci            return false;
25454aa6d63Sopenharmony_ci        }
25554aa6d63Sopenharmony_ci
25654aa6d63Sopenharmony_ci        if (propertyBlockArray.GetCapacity() < ZIP_HEAD_OF_SUBSIGNING_BLOCK_LENGTH)
25754aa6d63Sopenharmony_ci            return false;
25854aa6d63Sopenharmony_ci        uint32_t blockType;
25954aa6d63Sopenharmony_ci        propertyBlockArray.GetUInt32(OFFSET_ZERO, blockType);
26054aa6d63Sopenharmony_ci        uint32_t blockLength;
26154aa6d63Sopenharmony_ci        propertyBlockArray.GetUInt32(OFFSET_FOUR, blockLength);
26254aa6d63Sopenharmony_ci        uint32_t blockOffset;
26354aa6d63Sopenharmony_ci        propertyBlockArray.GetUInt32(OFFSET_EIGHT, blockOffset);
26454aa6d63Sopenharmony_ci
26554aa6d63Sopenharmony_ci        if (blockType != HapUtils::HAP_CODE_SIGN_BLOCK_ID) {
26654aa6d63Sopenharmony_ci            PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "code sign data not exist in hap " + hapFilePath);
26754aa6d63Sopenharmony_ci            return false;
26854aa6d63Sopenharmony_ci        }
26954aa6d63Sopenharmony_ci        auto ite = map.find(HapUtils::HAP_PROFILE_BLOCK_ID);
27054aa6d63Sopenharmony_ci        if (ite == map.end())
27154aa6d63Sopenharmony_ci            return false;
27254aa6d63Sopenharmony_ci        ByteBuffer profileArray = ite->second;
27354aa6d63Sopenharmony_ci        std::string profileArray_(profileArray.GetBufferPtr(), profileArray.GetCapacity());
27454aa6d63Sopenharmony_ci        std::string profileContent;
27554aa6d63Sopenharmony_ci        if (GetProfileContent(profileArray_, profileContent) < 0) {
27654aa6d63Sopenharmony_ci            SIGNATURE_TOOLS_LOGE("get profile content failed, file: %s", hapFilePath.c_str());
27754aa6d63Sopenharmony_ci            return false;
27854aa6d63Sopenharmony_ci        }
27954aa6d63Sopenharmony_ci        std::string suffix = fileNameArray[fileNameArray.size() - 1];
28054aa6d63Sopenharmony_ci        bool isCodeSign = VerifyCodeSignature::VerifyHap(hapFilePath, blockOffset, blockLength,
28154aa6d63Sopenharmony_ci                                                         suffix, profileContent);
28254aa6d63Sopenharmony_ci        if (!isCodeSign) {
28354aa6d63Sopenharmony_ci            SIGNATURE_TOOLS_LOGE("verify codesign failed, file: %s", hapFilePath.c_str());
28454aa6d63Sopenharmony_ci            return false;
28554aa6d63Sopenharmony_ci        }
28654aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGI("verify codesign success.");
28754aa6d63Sopenharmony_ci        return true;
28854aa6d63Sopenharmony_ci    }
28954aa6d63Sopenharmony_ci    SIGNATURE_TOOLS_LOGI("can not find codesign block.");
29054aa6d63Sopenharmony_ci    return true;
29154aa6d63Sopenharmony_ci}
29254aa6d63Sopenharmony_ci
29354aa6d63Sopenharmony_ciint VerifyHap::GetProfileContent(const std::string profile, std::string& ret)
29454aa6d63Sopenharmony_ci{
29554aa6d63Sopenharmony_ci    json obj = json::parse(profile, nullptr, false);
29654aa6d63Sopenharmony_ci    if (!obj.is_discarded() && obj.is_structured()) {
29754aa6d63Sopenharmony_ci        ret = profile;
29854aa6d63Sopenharmony_ci        return 0;
29954aa6d63Sopenharmony_ci    }
30054aa6d63Sopenharmony_ci    PKCS7Data p7Data;
30154aa6d63Sopenharmony_ci    if (p7Data.Parse(profile) < 0) {
30254aa6d63Sopenharmony_ci        ret = profile;
30354aa6d63Sopenharmony_ci        return -1;
30454aa6d63Sopenharmony_ci    }
30554aa6d63Sopenharmony_ci    if (p7Data.Verify() < 0) {
30654aa6d63Sopenharmony_ci        PrintErrorNumberMsg("PKCS7_VERIFY_ERROR", VERIFY_ERROR,
30754aa6d63Sopenharmony_ci                            "Verify profile pkcs7 failed! Profile is invalid");
30854aa6d63Sopenharmony_ci        ret = profile;
30954aa6d63Sopenharmony_ci        return -1;
31054aa6d63Sopenharmony_ci    }
31154aa6d63Sopenharmony_ci    if (p7Data.GetContent(ret) < 0) {
31254aa6d63Sopenharmony_ci        PrintErrorNumberMsg("PKCS7_VERIFY_ERROR", VERIFY_ERROR,
31354aa6d63Sopenharmony_ci                            "Check profile failed, signed profile content is not byte array");
31454aa6d63Sopenharmony_ci        ret = profile;
31554aa6d63Sopenharmony_ci        return -1;
31654aa6d63Sopenharmony_ci    }
31754aa6d63Sopenharmony_ci    return 0;
31854aa6d63Sopenharmony_ci}
31954aa6d63Sopenharmony_ci
32054aa6d63Sopenharmony_cibool VerifyHap::VerifyAppPkcs7(Pkcs7Context& pkcs7Context, const ByteBuffer& hapSignatureBlock)
32154aa6d63Sopenharmony_ci{
32254aa6d63Sopenharmony_ci    const unsigned char* pkcs7Block = reinterpret_cast<const unsigned char*>(hapSignatureBlock.GetBufferPtr());
32354aa6d63Sopenharmony_ci    uint32_t pkcs7Len = static_cast<unsigned int>(hapSignatureBlock.GetCapacity());
32454aa6d63Sopenharmony_ci    if (!VerifyHapOpensslUtils::ParsePkcs7Package(pkcs7Block, pkcs7Len, pkcs7Context)) {
32554aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("parse pkcs7 failed");
32654aa6d63Sopenharmony_ci        return false;
32754aa6d63Sopenharmony_ci    }
32854aa6d63Sopenharmony_ci    if (!VerifyHapOpensslUtils::GetCertChains(pkcs7Context.p7, pkcs7Context)) {
32954aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("GetCertChains from pkcs7 failed");
33054aa6d63Sopenharmony_ci        return false;
33154aa6d63Sopenharmony_ci    }
33254aa6d63Sopenharmony_ci    if (!VerifyHapOpensslUtils::VerifyPkcs7(pkcs7Context)) {
33354aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("verify signature failed");
33454aa6d63Sopenharmony_ci        return false;
33554aa6d63Sopenharmony_ci    }
33654aa6d63Sopenharmony_ci    return true;
33754aa6d63Sopenharmony_ci}
33854aa6d63Sopenharmony_ci
33954aa6d63Sopenharmony_cibool VerifyHap::GetDigestAndAlgorithm(Pkcs7Context& digest)
34054aa6d63Sopenharmony_ci{
34154aa6d63Sopenharmony_ci    /*
34254aa6d63Sopenharmony_ci     * contentinfo format:
34354aa6d63Sopenharmony_ci     * int: version
34454aa6d63Sopenharmony_ci     * int: block number
34554aa6d63Sopenharmony_ci     * digest blocks:
34654aa6d63Sopenharmony_ci     * each digest block format:
34754aa6d63Sopenharmony_ci     * int: length of sizeof(digestblock) - 4
34854aa6d63Sopenharmony_ci     * int: Algorithm ID
34954aa6d63Sopenharmony_ci     * int: length of digest
35054aa6d63Sopenharmony_ci     * byte[]: digest
35154aa6d63Sopenharmony_ci     */
35254aa6d63Sopenharmony_ci     /* length of sizeof(digestblock - 4) */
35354aa6d63Sopenharmony_ci    int32_t digestBlockLen;
35454aa6d63Sopenharmony_ci    if (!digest.content.GetInt32(DIGEST_BLOCK_LEN_OFFSET, digestBlockLen)) {
35554aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("get digestBlockLen failed");
35654aa6d63Sopenharmony_ci        return false;
35754aa6d63Sopenharmony_ci    }
35854aa6d63Sopenharmony_ci    /* Algorithm ID */
35954aa6d63Sopenharmony_ci    if (!digest.content.GetInt32(DIGEST_ALGORITHM_OFFSET, digest.digestAlgorithm)) {
36054aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("get digestAlgorithm failed");
36154aa6d63Sopenharmony_ci        return false;
36254aa6d63Sopenharmony_ci    }
36354aa6d63Sopenharmony_ci    /* length of digest */
36454aa6d63Sopenharmony_ci    int32_t digestlen;
36554aa6d63Sopenharmony_ci    if (!digest.content.GetInt32(DIGEST_LEN_OFFSET, digestlen)) {
36654aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("get digestlen failed");
36754aa6d63Sopenharmony_ci        return false;
36854aa6d63Sopenharmony_ci    }
36954aa6d63Sopenharmony_ci    int32_t sum = sizeof(digestlen) + sizeof(digest.digestAlgorithm) + digestlen;
37054aa6d63Sopenharmony_ci    if (sum != digestBlockLen) {
37154aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("digestBlockLen: %d is not equal to sum: %d",
37254aa6d63Sopenharmony_ci                             digestBlockLen, sum);
37354aa6d63Sopenharmony_ci        return false;
37454aa6d63Sopenharmony_ci    }
37554aa6d63Sopenharmony_ci    /* set position to the digest start point */
37654aa6d63Sopenharmony_ci    digest.content.SetPosition(DIGEST_OFFSET_IN_CONTENT);
37754aa6d63Sopenharmony_ci    /* set limit to the digest end point */
37854aa6d63Sopenharmony_ci    digest.content.SetLimit(DIGEST_OFFSET_IN_CONTENT + digestlen);
37954aa6d63Sopenharmony_ci    digest.content.Slice();
38054aa6d63Sopenharmony_ci    return true;
38154aa6d63Sopenharmony_ci}
38254aa6d63Sopenharmony_ci
38354aa6d63Sopenharmony_ciint32_t VerifyHap::WriteVerifyOutput(Pkcs7Context& pkcs7Context, std::vector<int8_t>& profile, Options* options)
38454aa6d63Sopenharmony_ci{
38554aa6d63Sopenharmony_ci    if (pkcs7Context.certChain.size() > 0) {
38654aa6d63Sopenharmony_ci        bool flag = VerifyHap::HapOutPutCertChain(pkcs7Context.certChain[0],
38754aa6d63Sopenharmony_ci            options->GetString(Options::OUT_CERT_CHAIN));
38854aa6d63Sopenharmony_ci        if (!flag) {
38954aa6d63Sopenharmony_ci            SIGNATURE_TOOLS_LOGE("out put cert chain failed");
39054aa6d63Sopenharmony_ci            return IO_ERROR;
39154aa6d63Sopenharmony_ci        }
39254aa6d63Sopenharmony_ci    }
39354aa6d63Sopenharmony_ci    if (pkcs7Context.p7 == nullptr) {
39454aa6d63Sopenharmony_ci        std::string p7bContent(profile.begin(), profile.end());
39554aa6d63Sopenharmony_ci        bool writeFlag = FileUtils::Write(p7bContent, options->GetString(Options::OUT_PROFILE)) < 0;
39654aa6d63Sopenharmony_ci        if (writeFlag) {
39754aa6d63Sopenharmony_ci            SIGNATURE_TOOLS_LOGE("p7b write to file falied!\n");
39854aa6d63Sopenharmony_ci            return IO_ERROR;
39954aa6d63Sopenharmony_ci        }
40054aa6d63Sopenharmony_ci        return RET_OK;
40154aa6d63Sopenharmony_ci    }
40254aa6d63Sopenharmony_ci    bool pkcs7flag = VerifyHap::HapOutPutPkcs7(pkcs7Context.p7, options->GetString(Options::OUT_PROFILE));
40354aa6d63Sopenharmony_ci    if (!pkcs7flag) {
40454aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("out put p7b failed");
40554aa6d63Sopenharmony_ci        return IO_ERROR;
40654aa6d63Sopenharmony_ci    }
40754aa6d63Sopenharmony_ci    return RET_OK;
40854aa6d63Sopenharmony_ci}
40954aa6d63Sopenharmony_ci
41054aa6d63Sopenharmony_cibool VerifyHap::PrintCertChainToCmd(std::vector<X509*>& certChain)
41154aa6d63Sopenharmony_ci{
41254aa6d63Sopenharmony_ci    BIO* outFd = BIO_new_fp(stdout, BIO_NOCLOSE);
41354aa6d63Sopenharmony_ci    if (!outFd) {
41454aa6d63Sopenharmony_ci        PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "The stdout stream may have errors");
41554aa6d63Sopenharmony_ci        return false;
41654aa6d63Sopenharmony_ci    }
41754aa6d63Sopenharmony_ci    uint64_t format = XN_FLAG_SEP_COMMA_PLUS; // Print according to RFC2253
41854aa6d63Sopenharmony_ci    uint64_t content = X509_FLAG_NO_EXTENSIONS | X509_FLAG_NO_ATTRIBUTES | X509_FLAG_NO_HEADER | X509_FLAG_NO_SIGDUMP;
41954aa6d63Sopenharmony_ci    int num = 0;
42054aa6d63Sopenharmony_ci    for (auto& cert : certChain) {
42154aa6d63Sopenharmony_ci        PrintMsg("+++++++++++++++++++++++++++++++++certificate #" + std::to_string(num) +
42254aa6d63Sopenharmony_ci                 "+++++++++++++++++++++++++++++++++++++");
42354aa6d63Sopenharmony_ci        if (!X509_print_ex(outFd, cert, format, content)) {
42454aa6d63Sopenharmony_ci            VerifyHapOpensslUtils::GetOpensslErrorMessage();
42554aa6d63Sopenharmony_ci            SIGNATURE_TOOLS_LOGE("print x509 cert to cmd failed");
42654aa6d63Sopenharmony_ci            BIO_free(outFd);
42754aa6d63Sopenharmony_ci            return false;
42854aa6d63Sopenharmony_ci        }
42954aa6d63Sopenharmony_ci        ++num;
43054aa6d63Sopenharmony_ci    }
43154aa6d63Sopenharmony_ci    BIO_free(outFd);
43254aa6d63Sopenharmony_ci    return true;
43354aa6d63Sopenharmony_ci}
43454aa6d63Sopenharmony_ci} // namespace SignatureTools
43554aa6d63Sopenharmony_ci} // namespace OHOS