1/*
2 * Copyright (c) 2024-2024 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#include "signature_tools_log.h"
16#include "signature_algorithm_helper.h"
17#include "bc_pkcs7_generator.h"
18#include "digest_common.h"
19#include "sign_hap.h"
20
21namespace OHOS {
22namespace SignatureTools {
23bool SignHap::Sign(DataSource* contents[], int32_t len, SignerConfig& config,
24                   std::vector<OptionalBlock>& optionalBlocks, ByteBuffer& result)
25{
26    if (len != CONTENT_NUBER) {
27        PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR,
28                            "zip contents len must is 3, now is " + std::to_string(len));
29        return false;
30    }
31    std::vector<SignatureAlgorithmHelper> algoClass = config.GetSignatureAlgorithms();
32    if (algoClass.empty()) {
33        PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "Signature Algorithms is empty");
34        return false;
35    }
36    SignatureAlgorithm algo = static_cast<SignatureAlgorithm>(algoClass[0].m_id);
37    SIGNATURE_TOOLS_LOGI("[SignHap] Signature Algorithm  is %d", algo);
38    int32_t nId = DigestCommon::GetDigestAlgorithmId(algo);
39    DigestParameter digestParam = HapSignerBlockUtils::GetDigestParameter(nId);
40    ByteBuffer digContext;
41    std::vector<std::pair<int32_t, ByteBuffer>> nidAndcontentDigestsVec;
42    // 1:Summarize corresponding content and optionalBlock
43    if (!ComputeDigests(digestParam, contents, CONTENT_NUBER, optionalBlocks, digContext)) {
44        SIGNATURE_TOOLS_LOGE("[SignHap] compute Digests failed");
45        return false;
46    }
47    SIGNATURE_TOOLS_LOGI("[SignHap] ComputeDigests %d", digContext.GetCapacity());
48    // 2:Encoding Summary Information
49    ByteBuffer digMessage;
50    std::pair<int32_t, ByteBuffer> nidAndcontentDigests = std::make_pair(algo, digContext);
51    nidAndcontentDigestsVec.push_back(nidAndcontentDigests);
52    EncodeListOfPairsToByteArray(digestParam, nidAndcontentDigestsVec, digMessage);
53
54    SIGNATURE_TOOLS_LOGI("[SignHap] EncodeListOfPairsToByteArray %d", digMessage.GetCapacity());
55    // 3:Encrypt the encoded summary information.
56    std::shared_ptr<Pkcs7Generator> pkcs7Generator = std::make_shared<BCPkcs7Generator>();
57    std::string digMessageData(digMessage.GetBufferPtr(), digMessage.GetCapacity());
58    std::string ret;
59    if (pkcs7Generator->GenerateSignedData(digMessageData, &config, ret) != 0) {
60        SIGNATURE_TOOLS_LOGE("[SignHap] Generate Signed Data failed");
61        return false;
62    }
63    SIGNATURE_TOOLS_LOGI("[SignHap] GenerateSignedData %lu", static_cast<unsigned long>(ret.size()));
64    bool checkGenerateHapSigningBlockFlag = GenerateHapSigningBlock(ret, optionalBlocks,
65                                                                    config.GetCompatibleVersion(), result);
66    if (!checkGenerateHapSigningBlockFlag) {
67        PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "Generate Hap Signing Block failed");
68        return false;
69    }
70    SIGNATURE_TOOLS_LOGI("[SignHap] GenerateHapSigningBlock %d", result.GetCapacity());
71    return true;
72}
73
74bool SignHap::ComputeDigests(const DigestParameter& digestParam, DataSource* contents[], int32_t len,
75                             const std::vector<OptionalBlock>& optionalBlocks, ByteBuffer& result)
76{
77    ByteBuffer chunkDigest;
78    bool ret = HapSignerBlockUtils::ComputeDigestsForEachChunk(digestParam, contents, len, chunkDigest);
79    if (!ret) {
80        PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "Compute Content Digests failed");
81        return false;
82    }
83    bool checkComputeDigestsWithOptionalBlockFlag =
84        HapSignerBlockUtils::ComputeDigestsWithOptionalBlock(digestParam, optionalBlocks, chunkDigest, result);
85    if (!checkComputeDigestsWithOptionalBlockFlag) {
86        PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "Compute Final Digests failed");
87        return false;
88    }
89    return true;
90}
91
92void SignHap::EncodeListOfPairsToByteArray(const DigestParameter& digestParam,
93                                           const std::vector<std::pair<int32_t,
94                                           ByteBuffer>>&nidAndcontentDigests, ByteBuffer& result)
95{
96    int encodeSize = 0;
97    encodeSize += INT_SIZE + INT_SIZE;
98    for (const auto& pair : nidAndcontentDigests) {
99        encodeSize += INT_SIZE + INT_SIZE + INT_SIZE + pair.second.GetCapacity();
100    }
101    result.SetCapacity(encodeSize);
102    result.PutInt32(CONTENT_VERSION); // version
103    result.PutInt32(BLOCK_NUMBER); // block number
104    for (const auto& pair : nidAndcontentDigests) {
105        auto second = pair.second;
106        result.PutInt32(INT_SIZE + INT_SIZE + second.GetCapacity());
107        result.PutInt32(pair.first);
108        result.PutInt32(second.GetCapacity());
109        result.Put(second);
110    }
111    return;
112}
113
114bool SignHap::GenerateHapSigningBlock(const std::string& hapSignatureSchemeBlock,
115                                      std::vector<OptionalBlock>& optionalBlocks,
116                                      int compatibleVersion, ByteBuffer& result)
117{
118    // FORMAT:
119    // Proof-of-Rotation pairs(optional):
120    // uint32:type
121    // uint32:length
122    // uint32:offset
123    // Property pairs(optional):
124    // uint32:type
125    // uint32:length
126    // uint32:offset
127    // Profile capability pairs(optional):
128    // uint32:type
129    // uint32:length
130    // uint32:offset
131    // length bytes : app signing pairs
132    // uint32:type
133    // uint32:length
134    // uint32:offset
135    // repeated ID-value pairs(reserved extensions):
136    // length bytes : Proof-of-Rotation values
137    // length bytes : property values
138    // length bytes : profile capability values
139    // length bytes : signature schema values
140    // uint64: size
141    // uint128: magic
142    // uint32: version
143    long optionalBlockSize = 0L;
144    for (const auto& elem : optionalBlocks) optionalBlockSize += elem.optionalBlockValue.GetCapacity();
145    long resultSize = ((OPTIONAL_TYPE_SIZE + OPTIONAL_LENGTH_SIZE + OPTIONAL_OFFSET_SIZE) *
146                       (optionalBlocks.size() + 1)) +
147        optionalBlockSize +
148        hapSignatureSchemeBlock.size() +
149        BLOCK_COUNT + HapUtils::BLOCK_SIZE + BLOCK_MAGIC + BLOCK_VERSION;
150    if (resultSize > INT_MAX) {
151        SIGNATURE_TOOLS_LOGE("Illegal Argument. HapSigningBlock out of range: %ld", resultSize);
152        return false;
153    }
154    result.SetCapacity((int)resultSize);
155    std::unordered_map<int, int> typeAndOffsetMap;
156    int currentOffset = ((OPTIONAL_TYPE_SIZE + OPTIONAL_LENGTH_SIZE
157                         + OPTIONAL_OFFSET_SIZE) * (optionalBlocks.size() + 1));
158    int currentOffsetInBlockValue = 0;
159    int blockValueSizes = (int)(optionalBlockSize + hapSignatureSchemeBlock.size());
160    std::string blockValues(blockValueSizes, 0);
161    for (const auto& elem : optionalBlocks) {
162        if (memcpy_s(blockValues.data() + currentOffsetInBlockValue, blockValueSizes,
163            elem.optionalBlockValue.GetBufferPtr(),
164            elem.optionalBlockValue.GetCapacity()) != 0) {
165            SIGNATURE_TOOLS_LOGE("GenerateHapSigningBlock memcpy_s failed\n");
166            return false;
167        }
168        typeAndOffsetMap.insert({ elem.optionalType, currentOffset });
169        currentOffset += elem.optionalBlockValue.GetCapacity();
170        currentOffsetInBlockValue += elem.optionalBlockValue.GetCapacity();
171    }
172    if (memcpy_s(blockValues.data() + currentOffsetInBlockValue, blockValueSizes, hapSignatureSchemeBlock.data(),
173        hapSignatureSchemeBlock.size()) != 0) {
174        SIGNATURE_TOOLS_LOGE("GenerateHapSigningBlock memcpy_s failed\n");
175        return false;
176    }
177    typeAndOffsetMap.insert({ HapUtils::HAP_SIGNATURE_SCHEME_V1_BLOCK_ID, currentOffset });
178    ExtractedResult(optionalBlocks, result, typeAndOffsetMap);
179    result.PutInt32(HapUtils::HAP_SIGNATURE_SCHEME_V1_BLOCK_ID); // type
180    result.PutInt32(hapSignatureSchemeBlock.size()); // length
181    int offset = typeAndOffsetMap.at(HapUtils::HAP_SIGNATURE_SCHEME_V1_BLOCK_ID);
182    result.PutInt32(offset); // offset
183    result.PutData(blockValues.c_str(), blockValueSizes);
184    result.PutInt32(optionalBlocks.size() + 1); // Signing block count
185    result.PutInt64(resultSize); // length of hap signing block
186    std::vector<int8_t> signingBlockMagic = HapUtils::GetHapSigningBlockMagic(compatibleVersion);
187    result.PutData((const char*)signingBlockMagic.data(), signingBlockMagic.size()); // magic
188    result.PutInt32(HapUtils::GetHapSigningBlockVersion(compatibleVersion)); // version
189    return true;
190}
191
192void SignHap::ExtractedResult(std::vector<OptionalBlock>& optionalBlocks, ByteBuffer& result,
193                              std::unordered_map<int, int>& typeAndOffsetMap)
194{
195    int offset;
196    for (const auto& elem : optionalBlocks) {
197        result.PutInt32(elem.optionalType);  // type
198        result.PutInt32(elem.optionalBlockValue.GetCapacity());  // length
199        offset = typeAndOffsetMap.at(elem.optionalType);
200        result.PutInt32(offset);  // offset
201    }
202}
203} // namespace SignatureTools
204} // namespace OHOS