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 
16 #include "hap_signer_block_utils.h"
17 #include <cinttypes>
18 #include <climits>
19 #include <vector>
20 
21 #include "signature_info.h"
22 #include "algorithm"
23 #include "openssl/evp.h"
24 #include "securec.h"
25 #include "byte_buffer_data_source.h"
26 #include "file_data_source.h"
27 #include "digest_common.h"
28 //#include "verify_hap_openssl_utils.h"
29 #include "signature_tools_log.h"
30 #include "signature_tools_errno.h"
31 
32 namespace OHOS {
33 namespace SignatureTools {
34 const int64_t HapSignerBlockUtils::HAP_SIG_BLOCK_MAGIC_LOW_OLD = 2334950737560224072LL;
35 const int64_t HapSignerBlockUtils::HAP_SIG_BLOCK_MAGIC_HIGH_OLD = 3617552046287187010LL;
36 const int64_t HapSignerBlockUtils::HAP_SIG_BLOCK_MAGIC_LOW = 7451613641622775868LL;
37 const int64_t HapSignerBlockUtils::HAP_SIG_BLOCK_MAGIC_HIGH = 4497797983070462062LL;
38 
39 /* 1MB = 1024 * 1024 Bytes */
40 const int64_t HapSignerBlockUtils::CHUNK_SIZE = 1048576LL;
41 
42 const int32_t HapSignerBlockUtils::HAP_SIG_BLOCK_MIN_SIZE = 32;
43 const int32_t HapSignerBlockUtils::ZIP_HEAD_OF_SIGNING_BLOCK_LENGTH = 32;
44 
45 const int32_t HapSignerBlockUtils::ZIP_EOCD_SEG_MIN_SIZE = 22;
46 const int32_t HapSignerBlockUtils::ZIP_EOCD_SEGMENT_FLAG = 0x06054b50;
47 const int32_t HapSignerBlockUtils::ZIP_EOCD_COMMENT_LENGTH_OFFSET = 20;
48 const int32_t HapSignerBlockUtils::ZIP_CD_OFFSET_IN_EOCD = 16;
49 const int32_t HapSignerBlockUtils::ZIP_CD_SIZE_OFFSET_IN_EOCD = 12;
50 const int32_t HapSignerBlockUtils::ZIP_BLOCKS_NUM_NEED_DIGEST = 3;
51 
52 const char HapSignerBlockUtils::ZIP_FIRST_LEVEL_CHUNK_PREFIX = 0x5a;
53 const char HapSignerBlockUtils::ZIP_SECOND_LEVEL_CHUNK_PREFIX = 0xa5;
54 
55 /*
56  * The package of hap is ZIP format, and contains four segments: contents of Zip entry,
57  * hap signatures block, central directory and end of central directory.
58  * The function will find the data segment of hap signature block from hap file.
59  */
FindHapSignature(RandomAccessFile& hapFile, SignatureInfo& signInfo)60 bool HapSignerBlockUtils::FindHapSignature(RandomAccessFile& hapFile, SignatureInfo& signInfo)
61 {
62     std::pair<ByteBuffer, int64_t> eocdAndOffsetInFile;
63     if (!FindEocdInHap(hapFile, eocdAndOffsetInFile)) {
64         SIGNATURE_TOOLS_LOGE("find EoCD failed");
65         return false;
66     }
67 
68     signInfo.hapEocd = eocdAndOffsetInFile.first;
69     signInfo.hapEocdOffset = eocdAndOffsetInFile.second;
70     if (!GetCentralDirectoryOffset(signInfo.hapEocd, signInfo.hapEocdOffset, signInfo.hapCentralDirOffset)) {
71         SIGNATURE_TOOLS_LOGE("get CD offset failed");
72         PrintErrorNumberMsg("verify", VERIFY_ERROR, "ZIP End of Central Directory not found");
73         return false;
74     }
75 
76     if (!FindHapSigningBlock(hapFile, signInfo.hapCentralDirOffset, signInfo)) {
77         SIGNATURE_TOOLS_LOGE("find signing block failed");
78         return false;
79     }
80     return true;
81 }
82 
FindEocdInHap(RandomAccessFile& hapFile, std::pair<ByteBuffer, int64_t>& eocd)83 bool HapSignerBlockUtils::FindEocdInHap(RandomAccessFile& hapFile, std::pair<ByteBuffer, int64_t>& eocd)
84 {
85     /*
86      * EoCD has an optional comment block. Most hap packages do not contain this block.
87      * For hap packages without comment block, EoCD is the last 22 bytes of hap file.
88      * Try as a hap without comment block first to avoid unnecessarily reading more data.
89      */
90     if (FindEocdInHap(hapFile, 0, eocd)) {
91         SIGNATURE_TOOLS_LOGD("Find EoCD of Zip file");
92         return true;
93     }
94     /*
95      * If EoCD contain the comment block, we should find it from the offset of (fileLen - maxCommentSize - 22).
96      * The max size of comment block is 65535, because the comment length is an unsigned 16-bit number.
97      */
98     return FindEocdInHap(hapFile, USHRT_MAX, eocd);
99 }
100 
FindEocdInHap(RandomAccessFile& hapFile, unsigned short maxCommentSize, std::pair<ByteBuffer, int64_t>& eocd)101 bool HapSignerBlockUtils::FindEocdInHap(RandomAccessFile& hapFile, unsigned short maxCommentSize,
102                                         std::pair<ByteBuffer, int64_t>& eocd)
103 {
104     int64_t fileLength = hapFile.GetLength();
105     /* check whether has enough space for EoCD in the file. */
106     if (fileLength < ZIP_EOCD_SEG_MIN_SIZE) {
107         SIGNATURE_TOOLS_LOGE("file length %" PRId64 " is too smaller", fileLength);
108         return false;
109     }
110 
111     int32_t searchRange = static_cast<int>(maxCommentSize) + ZIP_EOCD_SEG_MIN_SIZE;
112     if (fileLength < static_cast<int64_t>(searchRange)) {
113         searchRange = static_cast<int>(fileLength);
114     }
115 
116     ByteBuffer searchEocdBuffer(searchRange);
117     int64_t searchRangeOffset = fileLength - searchEocdBuffer.GetCapacity();
118     int64_t ret = hapFile.ReadFileFullyFromOffset(searchEocdBuffer, searchRangeOffset);
119     if (ret < 0) {
120         SIGNATURE_TOOLS_LOGE("read data from hap file error: %" PRId64, ret);
121         return false;
122     }
123 
124     int32_t eocdOffsetInSearchBuffer = 0;
125     if (!FindEocdInSearchBuffer(searchEocdBuffer, eocdOffsetInSearchBuffer)) {
126         SIGNATURE_TOOLS_LOGE("eocd is not found");
127         return false;
128     }
129 
130     searchEocdBuffer.SetPosition(eocdOffsetInSearchBuffer);
131     searchEocdBuffer.Slice();
132     eocd.first = searchEocdBuffer;
133     eocd.second = searchRangeOffset + eocdOffsetInSearchBuffer;
134     return true;
135 }
136 
137 
138 /*
139 * 4-bytes: End of central directory flag
140 * 2-bytes: Number of this disk
141 * 2-bytes: Number of the disk with the start of central directory
142 * 2-bytes: Total number of entries in the central directory on this disk
143 * 2-bytes: Total number of entries in the central directory
144 * 4-bytes: Size of central directory
145 * 4-bytes: offset of central directory in zip file
146 * 2-bytes: ZIP file comment length, the value n is in the range of [0, 65535]
147 * n-bytes: ZIP Comment block data
148 *
149 * This function find Eocd by searching Eocd flag from input buffer(searchBuffer) and
150 * making sure the comment length is equal to the expected value.
151 */
FindEocdInSearchBuffer(ByteBuffer& searchBuffer, int& offset)152 bool HapSignerBlockUtils::FindEocdInSearchBuffer(ByteBuffer& searchBuffer, int& offset)
153 {
154     int32_t searchBufferSize = searchBuffer.GetCapacity();
155     if (searchBufferSize < ZIP_EOCD_SEG_MIN_SIZE) {
156         SIGNATURE_TOOLS_LOGE("The size of searchBuffer %d is smaller than min size of Eocd",
157                              searchBufferSize);
158         return false;
159     }
160 
161     int32_t calcCurrentOffset = searchBufferSize - ZIP_EOCD_SEG_MIN_SIZE;
162     while (calcCurrentOffset >= 0) {
163         int32_t hapEocdSegmentFlag;
164         if (searchBuffer.GetInt32(calcCurrentOffset, hapEocdSegmentFlag) &&
165             (hapEocdSegmentFlag == ZIP_EOCD_SEGMENT_FLAG)) {
166             unsigned short commentLength;
167             int32_t expectedCommentLength = searchBufferSize - ZIP_EOCD_SEG_MIN_SIZE - calcCurrentOffset;
168             if (searchBuffer.GetUInt16(calcCurrentOffset + ZIP_EOCD_COMMENT_LENGTH_OFFSET, commentLength) &&
169                 static_cast<int>(commentLength) == expectedCommentLength) {
170                 offset = calcCurrentOffset;
171                 return true;
172             }
173         }
174         calcCurrentOffset--;
175     }
176     return false;
177 }
178 
GetCentralDirectoryOffset(ByteBuffer& eocd, int64_t eocdOffset, int64_t& centralDirectoryOffset)179 bool HapSignerBlockUtils::GetCentralDirectoryOffset(ByteBuffer& eocd, int64_t eocdOffset,
180                                                     int64_t& centralDirectoryOffset)
181 {
182     uint32_t offsetValue;
183     uint32_t sizeValue;
184     if (!eocd.GetUInt32(ZIP_CD_OFFSET_IN_EOCD, offsetValue) ||
185         !eocd.GetUInt32(ZIP_CD_SIZE_OFFSET_IN_EOCD, sizeValue)) {
186         SIGNATURE_TOOLS_LOGE("GetUInt32 failed");
187         return false;
188     }
189 
190     centralDirectoryOffset = static_cast<int64_t>(offsetValue);
191     if (centralDirectoryOffset > eocdOffset) {
192         SIGNATURE_TOOLS_LOGE("centralDirOffset %" PRId64 " is larger than eocdOffset %" PRId64,
193                              centralDirectoryOffset, eocdOffset);
194         return false;
195     }
196 
197     int64_t centralDirectorySize = static_cast<int64_t>(sizeValue);
198     if (centralDirectoryOffset + centralDirectorySize != eocdOffset) {
199         SIGNATURE_TOOLS_LOGE("centralDirOffset %" PRId64 " add centralDirSize %" PRId64 " is"
200                              " not equal to eocdOffset %" PRId64, centralDirectoryOffset,
201                              centralDirectorySize, eocdOffset);
202         return false;
203     }
204     return true;
205 }
206 
GetCentralDirectorySize(ByteBuffer& eocd, long& centralDirectorySize)207 bool HapSignerBlockUtils::GetCentralDirectorySize(ByteBuffer& eocd, long& centralDirectorySize)
208 {
209     uint32_t cdSize;
210     if (!eocd.GetUInt32(ZIP_CD_SIZE_OFFSET_IN_EOCD, cdSize)) {
211         SIGNATURE_TOOLS_LOGE("GetUInt32 failed");
212         return false;
213     }
214     centralDirectorySize = (long)cdSize;
215     return true;
216 }
217 
SetUnsignedInt32(ByteBuffer& buffer, int32_t offset, int64_t value)218 bool HapSignerBlockUtils::SetUnsignedInt32(ByteBuffer& buffer, int32_t offset, int64_t value)
219 {
220     if ((value < 0) || (value > static_cast<int64_t>(UINT_MAX))) {
221         SIGNATURE_TOOLS_LOGE("uint32 value of out range: %" PRId64, value);
222         return false;
223     }
224     buffer.PutInt32(offset, static_cast<int>(value));
225     return true;
226 }
227 
FindHapSigningBlock(RandomAccessFile& hapFile, int64_t centralDirOffset, SignatureInfo& signInfo)228 bool HapSignerBlockUtils::FindHapSigningBlock(RandomAccessFile& hapFile, int64_t centralDirOffset,
229                                               SignatureInfo& signInfo)
230 {
231     if (centralDirOffset < HAP_SIG_BLOCK_MIN_SIZE) {
232         SIGNATURE_TOOLS_LOGE("HAP too small for HAP Signing Block: %" PRId64, centralDirOffset);
233         return false;
234     }
235     /*
236      * read hap signing block head, it's format:
237      * int32: blockCount
238      * int64: size
239      * 16 bytes: magic
240      * int32: version
241      */
242     ByteBuffer hapBlockHead(ZIP_HEAD_OF_SIGNING_BLOCK_LENGTH);
243     int64_t ret = hapFile.ReadFileFullyFromOffset(hapBlockHead,
244                                                   centralDirOffset - hapBlockHead.GetCapacity());
245     if (ret < 0) {
246         SIGNATURE_TOOLS_LOGE("read hapBlockHead error: %" PRId64, ret);
247         return false;
248     }
249     HapSignBlockHead hapSignBlockHead;
250     if (!ParseSignBlockHead(hapSignBlockHead, hapBlockHead)) {
251         SIGNATURE_TOOLS_LOGE("ParseSignBlockHead failed");
252         return false;
253     }
254 
255     if (!CheckSignBlockHead(hapSignBlockHead)) {
256         SIGNATURE_TOOLS_LOGE("hapSignBlockHead is invalid");
257         return false;
258     }
259 
260     signInfo.version = hapSignBlockHead.version;
261     int64_t blockArrayLen = hapSignBlockHead.hapSignBlockSize - ZIP_HEAD_OF_SIGNING_BLOCK_LENGTH;
262     int64_t hapSignBlockOffset = centralDirOffset - hapSignBlockHead.hapSignBlockSize;
263     if (hapSignBlockOffset < 0) {
264         SIGNATURE_TOOLS_LOGE("HAP Signing Block offset out of range %" PRId64, hapSignBlockOffset);
265         return false;
266     }
267     signInfo.hapSigningBlockOffset = hapSignBlockOffset;
268     return FindHapSubSigningBlock(hapFile, hapSignBlockHead.blockCount,
269                                   blockArrayLen, hapSignBlockOffset, signInfo);
270 }
271 
CheckSignBlockHead(const HapSignBlockHead& hapSignBlockHead)272 bool HapSignerBlockUtils::CheckSignBlockHead(const HapSignBlockHead& hapSignBlockHead)
273 {
274     int64_t magicLow = HAP_SIG_BLOCK_MAGIC_LOW;
275     int64_t magicHigh = HAP_SIG_BLOCK_MAGIC_HIGH;
276     if (hapSignBlockHead.version < VERSION_FOR_NEW_MAGIC_NUM) {
277         magicLow = HAP_SIG_BLOCK_MAGIC_LOW_OLD;
278         magicHigh = HAP_SIG_BLOCK_MAGIC_HIGH_OLD;
279     }
280 
281     if ((hapSignBlockHead.hapSignBlockMagicLo != magicLow) ||
282         (hapSignBlockHead.hapSignBlockMagicHi != magicHigh)) {
283         SIGNATURE_TOOLS_LOGE("No HAP Signing Block before ZIP Central Directory");
284         return false;
285     }
286 
287     if ((hapSignBlockHead.hapSignBlockSize < ZIP_HEAD_OF_SIGNING_BLOCK_LENGTH) ||
288         (hapSignBlockHead.hapSignBlockSize > MAX_HAP_SIGN_BLOCK_SIZE)) {
289         SIGNATURE_TOOLS_LOGE("HAP Signing Block size out of range %" PRId64,
290                              hapSignBlockHead.hapSignBlockSize);
291         return false;
292     }
293 
294     if (hapSignBlockHead.blockCount > MAX_BLOCK_COUNT) {
295         SIGNATURE_TOOLS_LOGE("HAP Signing Block count out of range %d", hapSignBlockHead.blockCount);
296         return false;
297     }
298 
299     return true;
300 }
301 
ParseSignBlockHead(HapSignBlockHead& hapSignBlockHead, ByteBuffer& hapBlockHead)302 bool HapSignerBlockUtils::ParseSignBlockHead(HapSignBlockHead& hapSignBlockHead, ByteBuffer& hapBlockHead)
303 {
304     return hapBlockHead.GetInt32(hapSignBlockHead.blockCount) &&
305         hapBlockHead.GetInt64(hapSignBlockHead.hapSignBlockSize) &&
306         hapBlockHead.GetInt64(hapSignBlockHead.hapSignBlockMagicLo) &&
307         hapBlockHead.GetInt64(hapSignBlockHead.hapSignBlockMagicHi) &&
308         hapBlockHead.GetInt32(hapSignBlockHead.version);
309 }
310 
ParseSubSignBlockHead(HapSubSignBlockHead& subSignBlockHead, ByteBuffer& hapBlockHead)311 bool HapSignerBlockUtils::ParseSubSignBlockHead(HapSubSignBlockHead& subSignBlockHead,
312                                                 ByteBuffer& hapBlockHead)
313 {
314     return hapBlockHead.GetUInt32(subSignBlockHead.type) &&
315         hapBlockHead.GetUInt32(subSignBlockHead.length) &&
316         hapBlockHead.GetUInt32(subSignBlockHead.offset);
317 }
318 
319 /*
320  * Hap Sign Block Format:
321  * HapSubSignBlock1_Head
322  * HapSubSignBlock2_Head
323  * ...
324  * HapSubSignBlockn_Head
325  * HapSubSignBlock1_data
326  * HapSubSignBlock2_data
327  * ...
328  * HapSubSignBlockn_data
329  * hap signing block head
330  *
331  * This function reads the head of the HapSubSignBlocks,
332  * and then reads the corresponding data of each block according to the offset provided by the head
333  */
FindHapSubSigningBlock(RandomAccessFile& hapFile, int32_t blockCount, int64_t blockArrayLen, int64_t hapSignBlockOffset, SignatureInfo& signInfo)334 bool HapSignerBlockUtils::FindHapSubSigningBlock(RandomAccessFile& hapFile,
335                                                  int32_t blockCount,
336                                                  int64_t blockArrayLen,
337                                                  int64_t hapSignBlockOffset,
338                                                  SignatureInfo& signInfo)
339 {
340     int64_t offsetMax = hapSignBlockOffset + blockArrayLen;
341     int64_t readLen = 0;
342     int64_t readHeadOffset = hapSignBlockOffset;
343     for (int32_t i = 0; i < blockCount; i++) {
344         ByteBuffer hapBlockHead(ZIP_CD_SIZE_OFFSET_IN_EOCD);
345         int64_t ret = hapFile.ReadFileFullyFromOffset(hapBlockHead, readHeadOffset);
346         if (ret < 0) {
347             return false;
348         }
349         HapSubSignBlockHead subSignBlockHead;
350         if (!ParseSubSignBlockHead(subSignBlockHead, hapBlockHead)) {
351             SIGNATURE_TOOLS_LOGE("ParseSubSignBlockHead failed");
352             return false;
353         }
354         readLen += sizeof(HapSubSignBlockHead);
355 
356         readHeadOffset += sizeof(HapSubSignBlockHead);
357         if (readHeadOffset > offsetMax) {
358             SIGNATURE_TOOLS_LOGE("find %dst next head offset error", i);
359             return false;
360         }
361 
362         int64_t headOffset = static_cast<int64_t>(subSignBlockHead.offset);
363         int64_t headLength = static_cast<int64_t>(subSignBlockHead.length);
364         /* check subSignBlockHead */
365         if ((offsetMax - headOffset) < hapSignBlockOffset) {
366             SIGNATURE_TOOLS_LOGE("Find %dst subblock data offset error", i);
367             return false;
368         }
369         if ((blockArrayLen - headLength) < readLen) {
370             SIGNATURE_TOOLS_LOGE("no enough data to be read for %dst subblock", i);
371             return false;
372         }
373 
374         int64_t dataOffset = hapSignBlockOffset + headOffset;
375         ByteBuffer signBuffer(subSignBlockHead.length);
376         if ((ret = hapFile.ReadFileFullyFromOffset(signBuffer, dataOffset)) < 0) {
377             SIGNATURE_TOOLS_LOGE("read %dst subblock error: %" PRId64, i, ret);
378             return false;
379         }
380         readLen += headLength;
381 
382         if (!ClassifyHapSubSigningBlock(signInfo, signBuffer, subSignBlockHead.type)) {
383             SIGNATURE_TOOLS_LOGE("subSigningBlock error, type is %d", subSignBlockHead.type);
384             return false;
385         }
386     }
387 
388     /* size of block must be equal to the sum of all subblocks length */
389     if (readLen != blockArrayLen) {
390         SIGNATURE_TOOLS_LOGE("Len: %" PRId64 " is not equal blockArrayLen: %" PRId64,
391                              readLen, blockArrayLen);
392         return false;
393     }
394     return true;
395 }
396 
ClassifyHapSubSigningBlock(SignatureInfo& signInfo, const ByteBuffer& subBlock, uint32_t type)397 bool HapSignerBlockUtils::ClassifyHapSubSigningBlock(SignatureInfo& signInfo,
398                                                      const ByteBuffer& subBlock, uint32_t type)
399 {
400     bool ret = false;
401     switch (type) {
402         case HAP_SIGN_BLOB:
403             {
404                 if (signInfo.hapSignatureBlock.GetCapacity() != 0) {
405                     SIGNATURE_TOOLS_LOGE("find more than one hap sign block");
406                     break;
407                 }
408                 signInfo.hapSignatureBlock = subBlock;
409                 ret = true;
410                 break;
411             }
412         case PROFILE_BLOB:
413         case PROOF_ROTATION_BLOB:
414         case PROPERTY_BLOB:
415             {
416                 OptionalBlock optionalBlockObject;
417                 optionalBlockObject.optionalType = static_cast<int>(type);
418                 optionalBlockObject.optionalBlockValue = subBlock;
419                 signInfo.optionBlocks.push_back(optionalBlockObject);
420                 ret = true;
421                 break;
422             }
423         default:
424             break;
425     }
426     return ret;
427 }
428 
GetOptionalBlockIndex(std::vector<OptionalBlock>& optionBlocks, int32_t type, int& index)429 bool HapSignerBlockUtils::GetOptionalBlockIndex(std::vector<OptionalBlock>& optionBlocks,
430                                                 int32_t type,
431                                                 int& index)
432 {
433     int32_t len = static_cast<int>(optionBlocks.size());
434     for (int32_t i = 0; i < len; i++) {
435         if (optionBlocks[i].optionalType == type) {
436             index = i;
437             return true;
438         }
439     }
440     SIGNATURE_TOOLS_LOGE("get optional block type:%d failed.", type);
441     return false;
442 }
443 
VerifyHapIntegrity( Pkcs7Context& digestInfo, RandomAccessFile& hapFile, SignatureInfo& signInfo)444 bool HapSignerBlockUtils::VerifyHapIntegrity(
445     Pkcs7Context& digestInfo, RandomAccessFile& hapFile, SignatureInfo& signInfo)
446 {
447     if (!SetUnsignedInt32(signInfo.hapEocd, ZIP_CD_OFFSET_IN_EOCD, signInfo.hapSigningBlockOffset)) {
448         SIGNATURE_TOOLS_LOGE("Set central dir offset failed");
449         return false;
450     }
451 
452     int64_t centralDirSize = signInfo.hapEocdOffset - signInfo.hapCentralDirOffset;
453     FileDataSource contentsZip(hapFile, 0, signInfo.hapSigningBlockOffset, 0);
454     FileDataSource centralDir(hapFile, signInfo.hapCentralDirOffset, centralDirSize, 0);
455     ByteBufferDataSource eocd(signInfo.hapEocd);
456     DataSource* content[ZIP_BLOCKS_NUM_NEED_DIGEST] = {&contentsZip, &centralDir, &eocd};
457     int32_t nId = DigestCommon::GetDigestAlgorithmId(digestInfo.digestAlgorithm);
458     DigestParameter digestParam = GetDigestParameter(nId);
459     ByteBuffer chunkDigest;
460     if (!ComputeDigestsForEachChunk(digestParam, content, ZIP_BLOCKS_NUM_NEED_DIGEST, chunkDigest)) {
461         SIGNATURE_TOOLS_LOGE("Compute Content Digests failed, alg: %d", nId);
462         return false;
463     }
464 
465     ByteBuffer actualDigest;
466     if (!ComputeDigestsWithOptionalBlock(digestParam, signInfo.optionBlocks, chunkDigest, actualDigest)) {
467         SIGNATURE_TOOLS_LOGE("Compute Final Digests failed, alg: %d", nId);
468         return false;
469     }
470 
471     if (!digestInfo.content.IsEqual(actualDigest)) {
472         SIGNATURE_TOOLS_LOGE("digest of contents verify failed, alg %d", nId);
473         return false;
474     }
475     PrintMsg(std::string("Digest verify result: ") + "success" + ", DigestAlgorithm: "
476              + DigestCommon::GetDigestAlgorithmString(digestInfo.digestAlgorithm));
477 
478     return true;
479 }
480 
ComputeDigestsWithOptionalBlock(const DigestParameter& digestParam, const std::vector<OptionalBlock>& optionalBlocks, const ByteBuffer& chunkDigest, ByteBuffer& finalDigest)481 bool HapSignerBlockUtils::ComputeDigestsWithOptionalBlock(const DigestParameter& digestParam,
482                                                           const std::vector<OptionalBlock>& optionalBlocks,
483                                                           const ByteBuffer& chunkDigest,
484                                                           ByteBuffer& finalDigest)
485 {
486     unsigned char out[EVP_MAX_MD_SIZE];
487     int32_t digestLen = DigestCommon::GetDigest(chunkDigest, optionalBlocks, digestParam, out);
488     if (digestLen != digestParam.digestOutputSizeBytes) {
489         SIGNATURE_TOOLS_LOGE("GetDigest failed, outLen is not right, %u, %d",
490                              digestLen, digestParam.digestOutputSizeBytes);
491         return false;
492     }
493 
494     finalDigest.SetCapacity(digestParam.digestOutputSizeBytes);
495     finalDigest.PutData(0, reinterpret_cast<char*>(out), digestParam.digestOutputSizeBytes);
496     return true;
497 }
498 
GetSumOfChunkDigestLen(DataSource* contents[], int32_t len, int32_t chunkDigestLen, int& chunkCount, int& sumOfChunkDigestLen)499 bool HapSignerBlockUtils::GetSumOfChunkDigestLen(DataSource* contents[], int32_t len,
500                                                  int32_t chunkDigestLen, int& chunkCount,
501                                                  int& sumOfChunkDigestLen)
502 {
503     for (int32_t i = 0; i < len; i++) {
504         if (contents[i] == nullptr) {
505             SIGNATURE_TOOLS_LOGE("contents[%d] is nullptr", i);
506             return false;
507         }
508         contents[i]->Reset();
509         chunkCount += GetChunkCount(contents[i]->Remaining(), CHUNK_SIZE);
510     }
511 
512     if (chunkCount <= 0) {
513         SIGNATURE_TOOLS_LOGE("no content for digest");
514         return false;
515     }
516     if (chunkCount == 0) {
517         SIGNATURE_TOOLS_LOGE("no content for digest");
518         return false;
519     }
520     if (chunkDigestLen < 0 || ((INT_MAX - ZIP_CHUNK_DIGEST_PRIFIX_LEN) / chunkCount) < chunkDigestLen) {
521         SIGNATURE_TOOLS_LOGE("overflow chunkCount: %d, chunkDigestLen: %d",
522                              chunkCount, chunkDigestLen);
523         return false;
524     }
525 
526     sumOfChunkDigestLen = ZIP_CHUNK_DIGEST_PRIFIX_LEN + chunkCount * chunkDigestLen;
527     return true;
528 }
529 
ComputeDigestsForEachChunk(const DigestParameter& digestParam, DataSource* contents[], int32_t len, ByteBuffer& result)530 bool HapSignerBlockUtils::ComputeDigestsForEachChunk(const DigestParameter& digestParam,
531                                                      DataSource* contents[], int32_t len, ByteBuffer& result)
532 {
533     int32_t chunkCount = 0;
534     int32_t sumOfChunksLen = 0;
535     if (!GetSumOfChunkDigestLen(contents, len, digestParam.digestOutputSizeBytes, chunkCount, sumOfChunksLen)) {
536         SIGNATURE_TOOLS_LOGE("GetSumOfChunkDigestLen failed");
537         return false;
538     }
539     result.SetCapacity(sumOfChunksLen);
540     result.PutByte(0, ZIP_FIRST_LEVEL_CHUNK_PREFIX);
541     result.PutInt32(1, chunkCount);
542 
543     int32_t chunkIndex = 0;
544     unsigned char outBlock[EVP_MAX_MD_SIZE];
545     unsigned char zipChunkContentPrefix[ZIP_CHUNK_DIGEST_PRIFIX_LEN] = {
546     (unsigned char)ZIP_SECOND_LEVEL_CHUNK_PREFIX, 0, 0, 0, 0};
547 
548     int32_t zipOffset = ZIP_CHUNK_DIGEST_PRIFIX_LEN;
549     for (int32_t i = 0; i < len; i++) {
550         while (contents[i]->HasRemaining()) {
551             int32_t digestChunkSize = std::min(contents[i]->Remaining(), CHUNK_SIZE);
552             if (!InitDigestPrefix(digestParam, zipChunkContentPrefix, digestChunkSize)) {
553                 SIGNATURE_TOOLS_LOGE("InitDigestPrefix failed");
554                 return false;
555             }
556 
557             if (!contents[i]->ReadDataAndDigestUpdate(digestParam, digestChunkSize)) {
558                 SIGNATURE_TOOLS_LOGE("Copy Partial Buffer failed, count: %d", chunkIndex);
559                 return false;
560             }
561 
562             int32_t digestLen = DigestCommon::GetDigest(digestParam, outBlock);
563             if (digestLen != digestParam.digestOutputSizeBytes) {
564                 SIGNATURE_TOOLS_LOGE("GetDigest failed len: %d digestSizeBytes: %d",
565                                      digestLen, digestParam.digestOutputSizeBytes);
566                 return false;
567             }
568             result.PutData(zipOffset, reinterpret_cast<char*>(outBlock), digestParam.digestOutputSizeBytes);
569             zipOffset += digestLen;
570             chunkIndex++;
571         }
572     }
573     return true;
574 }
575 
GetDigestParameter(int32_t nId)576 DigestParameter HapSignerBlockUtils::GetDigestParameter(int32_t nId)
577 {
578     DigestParameter digestParam;
579     digestParam.digestOutputSizeBytes = DigestCommon::GetDigestAlgorithmOutputSizeBytes(nId);
580     digestParam.md = EVP_get_digestbynid(nId);
581     digestParam.ctxPtr = EVP_MD_CTX_create();
582     EVP_MD_CTX_init(digestParam.ctxPtr);
583     return digestParam;
584 }
585 
GetChunkCount(int64_t inputSize, int64_t chunkSize)586 int32_t HapSignerBlockUtils::GetChunkCount(int64_t inputSize, int64_t chunkSize)
587 {
588     if (chunkSize <= 0 || inputSize > LLONG_MAX - chunkSize) {
589         return 0;
590     }
591     if (chunkSize == 0)
592         return 0;
593     int64_t res = (inputSize + chunkSize - 1) / chunkSize;
594     if (res > INT_MAX || res < 0) {
595         return 0;
596     }
597     return static_cast<int>(res);
598 }
599 
InitDigestPrefix(const DigestParameter& digestParam, unsigned char(&chunkContentPrefix)[ZIP_CHUNK_DIGEST_PRIFIX_LEN], int32_t chunkLen)600 bool HapSignerBlockUtils::InitDigestPrefix(const DigestParameter& digestParam,
601                                            unsigned char(&chunkContentPrefix)[ZIP_CHUNK_DIGEST_PRIFIX_LEN],
602                                            int32_t chunkLen)
603 {
604     if (memcpy_s((chunkContentPrefix + 1), ZIP_CHUNK_DIGEST_PRIFIX_LEN - 1,
605                  (&chunkLen), sizeof(chunkLen)) != EOK) {
606         SIGNATURE_TOOLS_LOGE("memcpy_s failed");
607         return false;
608     }
609 
610     if (!DigestCommon::DigestInit(digestParam)) {
611         SIGNATURE_TOOLS_LOGE("DigestInit failed");
612         return false;
613     }
614 
615     if (!DigestCommon::DigestUpdate(digestParam, chunkContentPrefix, ZIP_CHUNK_DIGEST_PRIFIX_LEN)) {
616         SIGNATURE_TOOLS_LOGE("DigestUpdate failed");
617         return false;
618     }
619     return true;
620 }
621 
CreatTestZipFile(const std::string& pathFile, SignatureInfo& signInfo)622 int64_t HapSignerBlockUtils::CreatTestZipFile(const std::string& pathFile, SignatureInfo& signInfo)
623 {
624     std::ofstream hapFileInfo(pathFile.c_str(), std::ios::binary | std::ios::out | std::ios::trunc);
625     if (!hapFileInfo.is_open()) {
626         return 0;
627     }
628     char block[TEST_FILE_BLOCK_LENGTH] = {0};
629     /* input contents of ZIP entries */
630     hapFileInfo.seekp(0, std::ios_base::beg);
631     hapFileInfo.write(block, sizeof(block));
632     /* input sign block */
633     HapSubSignBlockHead signBlob;
634     HapSubSignBlockHead profileBlob;
635     HapSubSignBlockHead propertyBlob;
636     CreateHapSubSignBlockHead(signBlob, profileBlob, propertyBlob);
637     hapFileInfo.write(reinterpret_cast<char*>(&signBlob), sizeof(signBlob));
638     hapFileInfo.write(reinterpret_cast<char*>(&profileBlob), sizeof(profileBlob));
639     hapFileInfo.write(reinterpret_cast<char*>(&propertyBlob), sizeof(propertyBlob));
640     for (int32_t i = 0; i < TEST_FILE_BLOCK_COUNT; i++) {
641         hapFileInfo.write(block, sizeof(block));
642     }
643     int32_t blockCount = TEST_FILE_BLOCK_COUNT;
644     hapFileInfo.write(reinterpret_cast<char*>(&blockCount), sizeof(blockCount));
645     int64_t signBlockSize = (sizeof(HapSubSignBlockHead) + sizeof(block)) * TEST_FILE_BLOCK_COUNT +
646         HapSignerBlockUtils::ZIP_HEAD_OF_SIGNING_BLOCK_LENGTH;
647     hapFileInfo.write(reinterpret_cast<char*>(&signBlockSize), sizeof(signBlockSize));
648     int64_t magic = HapSignerBlockUtils::HAP_SIG_BLOCK_MAGIC_LOW_OLD;
649     hapFileInfo.write(reinterpret_cast<char*>(&magic), sizeof(magic));
650     magic = HapSignerBlockUtils::HAP_SIG_BLOCK_MAGIC_HIGH_OLD;
651     hapFileInfo.write(reinterpret_cast<char*>(&magic), sizeof(magic));
652     int32_t version = 1;
653     hapFileInfo.write(reinterpret_cast<char*>(&version), sizeof(version));
654     /* input central direction */
655     hapFileInfo.write(block, sizeof(block));
656     /* input end of central direction */
657     int32_t zidEocdSign = HapSignerBlockUtils::ZIP_EOCD_SEGMENT_FLAG;
658     hapFileInfo.write(reinterpret_cast<char*>(&zidEocdSign), sizeof(zidEocdSign));
659     hapFileInfo.write(reinterpret_cast<char*>(&magic), sizeof(magic));
660     uint32_t centralDirLen = sizeof(block);
661     hapFileInfo.write(reinterpret_cast<char*>(&centralDirLen), sizeof(centralDirLen));
662     uint32_t centralDirOffset = TEST_FILE_BLOCK_LENGTH + signBlockSize;
663     hapFileInfo.write(reinterpret_cast<char*>(&centralDirOffset), sizeof(centralDirOffset));
664     short eocdCommentLen = 0;
665     hapFileInfo.write(reinterpret_cast<char*>(&eocdCommentLen), sizeof(eocdCommentLen));
666     hapFileInfo.close();
667     signInfo.hapCentralDirOffset = centralDirOffset;
668     signInfo.hapEocdOffset = centralDirOffset + centralDirLen;
669     signInfo.hapSignatureBlock.SetCapacity(TEST_FILE_BLOCK_LENGTH);
670     signInfo.hapSignatureBlock.PutData(0, block, sizeof(block));
671     int64_t sumLen = signInfo.hapEocdOffset + sizeof(zidEocdSign) + sizeof(centralDirLen) +
672         sizeof(centralDirOffset) + sizeof(magic) + sizeof(eocdCommentLen);
673     return sumLen;
674 }
675 
CreateHapSubSignBlockHead(HapSubSignBlockHead& signBlob, HapSubSignBlockHead& profileBlob, HapSubSignBlockHead& propertyBlob)676 void HapSignerBlockUtils::CreateHapSubSignBlockHead(HapSubSignBlockHead& signBlob,
677                                                     HapSubSignBlockHead& profileBlob,
678                                                     HapSubSignBlockHead& propertyBlob)
679 {
680     signBlob.type = HAP_SIGN_BLOB;
681     signBlob.length = TEST_FILE_BLOCK_LENGTH;
682     signBlob.offset = sizeof(HapSubSignBlockHead) * TEST_FILE_BLOCK_COUNT;
683     propertyBlob.type = PROPERTY_BLOB;
684     propertyBlob.length = TEST_FILE_BLOCK_LENGTH;
685     propertyBlob.offset = profileBlob.offset + profileBlob.length;
686     profileBlob.type = PROFILE_BLOB;
687     profileBlob.length = TEST_FILE_BLOCK_LENGTH;
688     profileBlob.offset = signBlob.offset + signBlob.length;
689 }
690 } // namespace SignatureTools
691 } // namespace OHOS