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
32namespace OHOS {
33namespace SignatureTools {
34const int64_t HapSignerBlockUtils::HAP_SIG_BLOCK_MAGIC_LOW_OLD = 2334950737560224072LL;
35const int64_t HapSignerBlockUtils::HAP_SIG_BLOCK_MAGIC_HIGH_OLD = 3617552046287187010LL;
36const int64_t HapSignerBlockUtils::HAP_SIG_BLOCK_MAGIC_LOW = 7451613641622775868LL;
37const int64_t HapSignerBlockUtils::HAP_SIG_BLOCK_MAGIC_HIGH = 4497797983070462062LL;
38
39/* 1MB = 1024 * 1024 Bytes */
40const int64_t HapSignerBlockUtils::CHUNK_SIZE = 1048576LL;
41
42const int32_t HapSignerBlockUtils::HAP_SIG_BLOCK_MIN_SIZE = 32;
43const int32_t HapSignerBlockUtils::ZIP_HEAD_OF_SIGNING_BLOCK_LENGTH = 32;
44
45const int32_t HapSignerBlockUtils::ZIP_EOCD_SEG_MIN_SIZE = 22;
46const int32_t HapSignerBlockUtils::ZIP_EOCD_SEGMENT_FLAG = 0x06054b50;
47const int32_t HapSignerBlockUtils::ZIP_EOCD_COMMENT_LENGTH_OFFSET = 20;
48const int32_t HapSignerBlockUtils::ZIP_CD_OFFSET_IN_EOCD = 16;
49const int32_t HapSignerBlockUtils::ZIP_CD_SIZE_OFFSET_IN_EOCD = 12;
50const int32_t HapSignerBlockUtils::ZIP_BLOCKS_NUM_NEED_DIGEST = 3;
51
52const char HapSignerBlockUtils::ZIP_FIRST_LEVEL_CHUNK_PREFIX = 0x5a;
53const 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 */
60bool 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
83bool 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
101bool 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*/
152bool 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
179bool 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
207bool 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
218bool 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
228bool 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
272bool 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
302bool 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
311bool 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 */
334bool 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
397bool 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
429bool 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
444bool 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
481bool 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
499bool 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
530bool 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
576DigestParameter 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
586int32_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
600bool 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
622int64_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
676void 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