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
1654aa6d63Sopenharmony_ci#include "sign_bin.h"
1754aa6d63Sopenharmony_ci#include "param_constants.h"
1854aa6d63Sopenharmony_ci#include "file_utils.h"
1954aa6d63Sopenharmony_ci#include "block_head.h"
2054aa6d63Sopenharmony_ci#include "signature_block_types.h"
2154aa6d63Sopenharmony_ci#include "signature_block_tags.h"
2254aa6d63Sopenharmony_ci#include "hash_utils.h"
2354aa6d63Sopenharmony_ci#include "sign_content_info.h"
2454aa6d63Sopenharmony_ci#include "sign_head.h"
2554aa6d63Sopenharmony_ci#include "bc_pkcs7_generator.h"
2654aa6d63Sopenharmony_ci#include "params.h"
2754aa6d63Sopenharmony_ci
2854aa6d63Sopenharmony_cinamespace OHOS {
2954aa6d63Sopenharmony_cinamespace SignatureTools {
3054aa6d63Sopenharmony_ci
3154aa6d63Sopenharmony_cibool SignBin::Sign(SignerConfig& signerConfig, const std::map<std::string, std::string>& signParams)
3254aa6d63Sopenharmony_ci{
3354aa6d63Sopenharmony_ci    /* 1. Make block head, write to output file. */
3454aa6d63Sopenharmony_ci    std::string signCode = signParams.at(ParamConstants::PARAM_SIGN_CODE);
3554aa6d63Sopenharmony_ci    if (ParamConstants::ENABLE_SIGN_CODE == signCode) {
3654aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGW("can not sign bin with codesign.\n");
3754aa6d63Sopenharmony_ci    }
3854aa6d63Sopenharmony_ci    std::string inputFile = signParams.at(ParamConstants::PARAM_BASIC_INPUT_FILE);
3954aa6d63Sopenharmony_ci    std::string outputFile = signParams.at(ParamConstants::PARAM_BASIC_OUTPUT_FILE);
4054aa6d63Sopenharmony_ci    std::string profileFile = signParams.at(ParamConstants::PARAM_BASIC_PROFILE);
4154aa6d63Sopenharmony_ci    std::string profileSigned = signParams.at(ParamConstants::PARAM_BASIC_PROFILE_SIGNED);
4254aa6d63Sopenharmony_ci    bool writeBlockOk = WriteBlockDataToFile(inputFile, outputFile, profileFile, profileSigned);
4354aa6d63Sopenharmony_ci    if (!writeBlockOk) {
4454aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("The block head data made failed.");
4554aa6d63Sopenharmony_ci        FileUtils::DelDir(outputFile);
4654aa6d63Sopenharmony_ci        return false;
4754aa6d63Sopenharmony_ci    }
4854aa6d63Sopenharmony_ci    /* 2. Make sign data, and append write to output file */
4954aa6d63Sopenharmony_ci    std::string signAlg = signParams.at(ParamConstants::PARAM_BASIC_SIGANTURE_ALG);
5054aa6d63Sopenharmony_ci    bool writeSignDataOk = WriteSignDataToOutputFile(signerConfig, outputFile, signAlg);
5154aa6d63Sopenharmony_ci    if (!writeSignDataOk) {
5254aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("The sign data made failed.");
5354aa6d63Sopenharmony_ci        FileUtils::DelDir(outputFile);
5454aa6d63Sopenharmony_ci        return false;
5554aa6d63Sopenharmony_ci    }
5654aa6d63Sopenharmony_ci    /* 3. Make sign head data, and write to output file */
5754aa6d63Sopenharmony_ci    bool writeSignHeadDataOk = WriteSignHeadDataToOutputFile(inputFile, outputFile);
5854aa6d63Sopenharmony_ci    if (!writeSignHeadDataOk) {
5954aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("The sign head data made failed.");
6054aa6d63Sopenharmony_ci        FileUtils::DelDir(outputFile);
6154aa6d63Sopenharmony_ci        return false;
6254aa6d63Sopenharmony_ci    }
6354aa6d63Sopenharmony_ci    return true;
6454aa6d63Sopenharmony_ci}
6554aa6d63Sopenharmony_ci
6654aa6d63Sopenharmony_cibool SignBin::WriteBlockDataToFile(const std::string& inputFile, const std::string& outputFile,
6754aa6d63Sopenharmony_ci                                   const std::string& profileFile, const std::string& profileSigned)
6854aa6d63Sopenharmony_ci{
6954aa6d63Sopenharmony_ci    int64_t binFileLen = FileUtils::GetFileLen(inputFile);
7054aa6d63Sopenharmony_ci    int64_t profileDataLen = FileUtils::GetFileLen(profileFile);
7154aa6d63Sopenharmony_ci    bool isValid = CheckBinAndProfileLengthIsValid(binFileLen, profileDataLen);
7254aa6d63Sopenharmony_ci    if (!isValid) {
7354aa6d63Sopenharmony_ci        PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR,
7454aa6d63Sopenharmony_ci                            "file length is invalid, binFileLen: " + std::to_string(binFileLen) +
7554aa6d63Sopenharmony_ci                            "lld, profileDataLen: " + std::to_string(profileDataLen) + "lld");
7654aa6d63Sopenharmony_ci        return false;
7754aa6d63Sopenharmony_ci    }
7854aa6d63Sopenharmony_ci    int64_t offset = binFileLen + BlockHead::GetBlockLen() + BlockHead::GetBlockLen();
7954aa6d63Sopenharmony_ci    bool isOver = IsLongOverflowInteger(offset);
8054aa6d63Sopenharmony_ci    if (isOver) {
8154aa6d63Sopenharmony_ci        PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR,
8254aa6d63Sopenharmony_ci            "The profile block head offset is overflow interger range in sign bin, offset: "
8354aa6d63Sopenharmony_ci            + std::to_string(offset));
8454aa6d63Sopenharmony_ci        return false;
8554aa6d63Sopenharmony_ci    }
8654aa6d63Sopenharmony_ci    char isSigned = SignatureBlockTypes::GetProfileBlockTypes(profileSigned);
8754aa6d63Sopenharmony_ci    std::string proBlockByte =
8854aa6d63Sopenharmony_ci        BlockHead::GetBlockHead(isSigned, SignatureBlockTags::DEFAULT, (short)profileDataLen, (int)offset);
8954aa6d63Sopenharmony_ci    offset += profileDataLen;
9054aa6d63Sopenharmony_ci    isOver = IsLongOverflowInteger(offset);
9154aa6d63Sopenharmony_ci    if (isOver) {
9254aa6d63Sopenharmony_ci        PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR,
9354aa6d63Sopenharmony_ci            "The profile block head offset is overflow interger range in sign bin, offset: "
9454aa6d63Sopenharmony_ci            + std::to_string(offset));
9554aa6d63Sopenharmony_ci        return false;
9654aa6d63Sopenharmony_ci    }
9754aa6d63Sopenharmony_ci    std::string signBlockByte = BlockHead::GetBlockHead(
9854aa6d63Sopenharmony_ci        SignatureBlockTypes::SIGNATURE_BLOCK, SignatureBlockTags::DEFAULT, (short)0, (int)offset);
9954aa6d63Sopenharmony_ci    return WriteSignedBin(inputFile, proBlockByte, signBlockByte, profileFile, outputFile);
10054aa6d63Sopenharmony_ci}
10154aa6d63Sopenharmony_ci
10254aa6d63Sopenharmony_cistd::vector<int8_t> SignBin::GenerateFileDigest(const std::string& outputFile,
10354aa6d63Sopenharmony_ci                                                const std::string& signAlg)
10454aa6d63Sopenharmony_ci{
10554aa6d63Sopenharmony_ci    SignatureAlgorithmHelper signatureAlgorithmClass;
10654aa6d63Sopenharmony_ci    bool getAlgOk = Params::GetSignatureAlgorithm(signAlg, signatureAlgorithmClass);
10754aa6d63Sopenharmony_ci    if (!getAlgOk) {
10854aa6d63Sopenharmony_ci        PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "[SignHap] get Signature Algorithm failed.");
10954aa6d63Sopenharmony_ci        return std::vector<int8_t>();
11054aa6d63Sopenharmony_ci    }
11154aa6d63Sopenharmony_ci    std::string alg = signatureAlgorithmClass.m_contentDigestAlgorithm.GetDigestAlgorithm();
11254aa6d63Sopenharmony_ci    std::vector<int8_t> data = HashUtils::GetFileDigest(outputFile, alg);
11354aa6d63Sopenharmony_ci    if (data.empty()) {
11454aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("GetFileDigest failed.");
11554aa6d63Sopenharmony_ci        return std::vector<int8_t>();
11654aa6d63Sopenharmony_ci    }
11754aa6d63Sopenharmony_ci    std::vector<int8_t> outputChunk;
11854aa6d63Sopenharmony_ci    SignContentInfo contentInfo;
11954aa6d63Sopenharmony_ci    contentInfo.AddContentHashData(0, SignatureBlockTags::HASH_ROOT_4K, HashUtils::GetHashAlgsId(alg),
12054aa6d63Sopenharmony_ci                                   data.size(), data);
12154aa6d63Sopenharmony_ci    return contentInfo.GetByteContent();
12254aa6d63Sopenharmony_ci}
12354aa6d63Sopenharmony_ci
12454aa6d63Sopenharmony_cibool SignBin::WriteSignDataToOutputFile(SignerConfig& SignerConfig, const std::string& outputFile,
12554aa6d63Sopenharmony_ci                                        const std::string& signAlg)
12654aa6d63Sopenharmony_ci{
12754aa6d63Sopenharmony_ci    std::vector<int8_t> dig = GenerateFileDigest(outputFile, signAlg);
12854aa6d63Sopenharmony_ci    if (dig.empty()) {
12954aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("generateSignature verity digest is null.");
13054aa6d63Sopenharmony_ci        return false;
13154aa6d63Sopenharmony_ci    }
13254aa6d63Sopenharmony_ci    std::string retStr;
13354aa6d63Sopenharmony_ci    std::string signedData(dig.begin(), dig.end());
13454aa6d63Sopenharmony_ci    std::unique_ptr<Pkcs7Generator> generator = std::make_unique<BCPkcs7Generator>();
13554aa6d63Sopenharmony_ci    if (generator->GenerateSignedData(signedData, &SignerConfig, retStr)) {
13654aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("failed to GenerateSignedData!");
13754aa6d63Sopenharmony_ci        return false;
13854aa6d63Sopenharmony_ci    }
13954aa6d63Sopenharmony_ci    bool writeByteToOutFile = FileUtils::AppendWriteByteToFile(retStr, outputFile);
14054aa6d63Sopenharmony_ci    if (!writeByteToOutFile) {
14154aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("write signedData to outputFile failed!");
14254aa6d63Sopenharmony_ci        return false;
14354aa6d63Sopenharmony_ci    }
14454aa6d63Sopenharmony_ci    return true;
14554aa6d63Sopenharmony_ci}
14654aa6d63Sopenharmony_ci
14754aa6d63Sopenharmony_cibool SignBin::WriteSignHeadDataToOutputFile(const std::string& inputFile, const std::string& outputFile)
14854aa6d63Sopenharmony_ci{
14954aa6d63Sopenharmony_ci    int64_t size = FileUtils::GetFileLen(outputFile) - FileUtils::GetFileLen(inputFile) + SignHead::SIGN_HEAD_LEN;
15054aa6d63Sopenharmony_ci    bool isOver = IsLongOverflowInteger(size);
15154aa6d63Sopenharmony_ci    if (isOver) {
15254aa6d63Sopenharmony_ci        PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR,
15354aa6d63Sopenharmony_ci            "File size is Overflow integer range, size: " + std::to_string(size));
15454aa6d63Sopenharmony_ci        return false;
15554aa6d63Sopenharmony_ci    }
15654aa6d63Sopenharmony_ci    SignHead signHeadData;
15754aa6d63Sopenharmony_ci    std::vector<int8_t> signHeadByte = signHeadData.GetSignHead(size);
15854aa6d63Sopenharmony_ci    if (signHeadByte.empty()) {
15954aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("Failed to get sign head data!");
16054aa6d63Sopenharmony_ci        return false;
16154aa6d63Sopenharmony_ci    }
16254aa6d63Sopenharmony_ci    bool writeByteToOutFile =
16354aa6d63Sopenharmony_ci        FileUtils::AppendWriteByteToFile(std::string(signHeadByte.begin(), signHeadByte.end()), outputFile);
16454aa6d63Sopenharmony_ci    if (!writeByteToOutFile) {
16554aa6d63Sopenharmony_ci        SIGNATURE_TOOLS_LOGE("Failed to WriteByteToOutFile!");
16654aa6d63Sopenharmony_ci        return false;
16754aa6d63Sopenharmony_ci    }
16854aa6d63Sopenharmony_ci    return true;
16954aa6d63Sopenharmony_ci}
17054aa6d63Sopenharmony_ci
17154aa6d63Sopenharmony_cibool SignBin::CheckBinAndProfileLengthIsValid(int64_t binFileLen, int64_t profileDataLen)
17254aa6d63Sopenharmony_ci{
17354aa6d63Sopenharmony_ci    return binFileLen != -1 && profileDataLen != -1 && !IsLongOverflowShort(profileDataLen);
17454aa6d63Sopenharmony_ci}
17554aa6d63Sopenharmony_ci
17654aa6d63Sopenharmony_cibool SignBin::IsLongOverflowInteger(int64_t num)
17754aa6d63Sopenharmony_ci{
17854aa6d63Sopenharmony_ci    return (num - (num & 0xffffffffL)) != 0;
17954aa6d63Sopenharmony_ci}
18054aa6d63Sopenharmony_ci
18154aa6d63Sopenharmony_cibool SignBin::IsLongOverflowShort(int64_t num)
18254aa6d63Sopenharmony_ci{
18354aa6d63Sopenharmony_ci    return (num - (num & 0xffff)) != 0;
18454aa6d63Sopenharmony_ci}
18554aa6d63Sopenharmony_ci
18654aa6d63Sopenharmony_cibool SignBin::WriteSignedBin(const std::string& inputFile, const std::string& proBlockByte,
18754aa6d63Sopenharmony_ci                             const std::string& signBlockByte, const std::string& profileFile,
18854aa6d63Sopenharmony_ci                             const std::string& outputFile)
18954aa6d63Sopenharmony_ci{
19054aa6d63Sopenharmony_ci    // 1. write the input file to the output file.
19154aa6d63Sopenharmony_ci    bool writeInputOk = FileUtils::WriteInputToOutPut(inputFile, outputFile);
19254aa6d63Sopenharmony_ci    // 2. append write profile block head to the output file.
19354aa6d63Sopenharmony_ci    bool appendProfileHeadOk = FileUtils::AppendWriteByteToFile(proBlockByte, outputFile);
19454aa6d63Sopenharmony_ci    // 3. append write sign block head to the output file.
19554aa6d63Sopenharmony_ci    bool appendBlockHeadOk = FileUtils::AppendWriteByteToFile(signBlockByte, outputFile);
19654aa6d63Sopenharmony_ci    // 4. write profile src file to the output file.
19754aa6d63Sopenharmony_ci    bool appendProfileSrcOk = FileUtils::AppendWriteFileToFile(profileFile, outputFile);
19854aa6d63Sopenharmony_ci    if (!writeInputOk || !appendProfileHeadOk || !appendBlockHeadOk || !appendProfileSrcOk) {
19954aa6d63Sopenharmony_ci        PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "Failed to write signed bin");
20054aa6d63Sopenharmony_ci        return false;
20154aa6d63Sopenharmony_ci    }
20254aa6d63Sopenharmony_ci    return true;
20354aa6d63Sopenharmony_ci}
20454aa6d63Sopenharmony_ci
20554aa6d63Sopenharmony_ci} // namespace SignatureTools
20654aa6d63Sopenharmony_ci} // namespace OHOS