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 
21 namespace OHOS {
22 namespace SignatureTools {
Sign(DataSource* contents[], int32_t len, SignerConfig& config, std::vector<OptionalBlock>& optionalBlocks, ByteBuffer& result)23 bool 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 
ComputeDigests(const DigestParameter& digestParam, DataSource* contents[], int32_t len, const std::vector<OptionalBlock>& optionalBlocks, ByteBuffer& result)74 bool 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 
EncodeListOfPairsToByteArray(const DigestParameter& digestParam, const std::vector<std::pair<int32_t, ByteBuffer>>&nidAndcontentDigests, ByteBuffer& result)92 void 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 
GenerateHapSigningBlock(const std::string& hapSignatureSchemeBlock, std::vector<OptionalBlock>& optionalBlocks, int compatibleVersion, ByteBuffer& result)114 bool 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 
ExtractedResult(std::vector<OptionalBlock>& optionalBlocks, ByteBuffer& result, std::unordered_map<int, int>& typeAndOffsetMap)192 void 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