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