• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 int HapSigningBlockUtils::HAP_SIG_BLOCK_MIN_SIZE = 32;
41 const int HapSigningBlockUtils::ZIP_HEAD_OF_SIGNING_BLOCK_LENGTH = 32;
42 
43 const int HapSigningBlockUtils::ZIP_EOCD_SEG_MIN_SIZE = 22;
44 const int HapSigningBlockUtils::ZIP_EOCD_SEGMENT_FLAG = 0x06054b50;
45 const int HapSigningBlockUtils::ZIP_EOCD_COMMENT_LENGTH_OFFSET = 20;
46 const int HapSigningBlockUtils::ZIP_CD_OFFSET_IN_EOCD = 16;
47 const int HapSigningBlockUtils::ZIP_CD_SIZE_OFFSET_IN_EOCD = 12;
48 const int 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(LABEL, "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(LABEL, "get CD offset failed");
70         return false;
71     }
72 
73     if (!FindHapSigningBlock(hapFile, signInfo.hapCentralDirOffset, signInfo)) {
74         HAPVERIFY_LOG_ERROR(LABEL, "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(LABEL, "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(LABEL, "file length %{public}lld is too smaller", fileLength);
105         return false;
106     }
107 
108     int 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(LABEL, "read data from hap file error: %{public}lld", ret);
118         return false;
119     }
120 
121     int eocdOffsetInSearchBuffer = 0;
122     if (!FindEocdInSearchBuffer(searchEocdBuffer, eocdOffsetInSearchBuffer)) {
123         HAPVERIFY_LOG_ERROR(LABEL, "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     int searchBufferSize = searchBuffer.GetCapacity();
152     if (searchBufferSize < ZIP_EOCD_SEG_MIN_SIZE) {
153         HAPVERIFY_LOG_ERROR(LABEL, "The size of searchBuffer %{public}d is smaller than min size of Eocd",
154             searchBufferSize);
155         return false;
156     }
157 
158     int currentOffset = searchBufferSize - ZIP_EOCD_SEG_MIN_SIZE;
159     while (currentOffset >= 0) {
160         int hapEocdSegmentFlag;
161         if (searchBuffer.GetInt32(currentOffset, hapEocdSegmentFlag) &&
162             (hapEocdSegmentFlag == ZIP_EOCD_SEGMENT_FLAG)) {
163             unsigned short commentLength;
164             int 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     unsigned int offsetValue;
180     unsigned int 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(LABEL, "GetUInt32 failed");
184         return false;
185     }
186 
187     centralDirectoryOffset = static_cast<long long>(offsetValue);
188     if (centralDirectoryOffset > eocdOffset) {
189         HAPVERIFY_LOG_ERROR(LABEL, "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(LABEL, "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,int offset,long long value)203 bool HapSigningBlockUtils::SetUnsignedInt32(HapByteBuffer& buffer, int offset, long long value)
204 {
205     if ((value < 0) || (value > static_cast<long long>(UINT_MAX))) {
206         HAPVERIFY_LOG_ERROR(LABEL, "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(LABEL, "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(LABEL, "read hapBlockHead error: %{public}lld", ret);
231         return false;
232     }
233     HapSignBlockHead hapSignBlockHead;
234     if (!ParseSignBlockHead(hapSignBlockHead, hapBlockHead)) {
235         HAPVERIFY_LOG_ERROR(LABEL, "ParseSignBlockHead failed");
236         return false;
237     }
238 
239     if (!CheckSignBlockHead(hapSignBlockHead)) {
240         HAPVERIFY_LOG_ERROR(LABEL, "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(LABEL, "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(LABEL, "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(LABEL, "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(LABEL, "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 
294 /*
295  * Hap Sign Block Format:
296  * HapSubSignBlock1_Head
297  * HapSubSignBlock2_Head
298  * ...
299  * HapSubSignBlockn_Head
300  * HapSubSignBlock1_data
301  * HapSubSignBlock2_data
302  * ...
303  * HapSubSignBlockn_data
304  * hap signing block head
305  *
306  * This function reads the head of the HapSubSignBlocks,
307  * and then reads the corresponding data of each block according to the offset provided by the head
308  */
FindHapSubSigningBlock(RandomAccessFile & hapFile,int blockCount,long long blockArrayLen,long long hapSignBlockOffset,SignatureInfo & signInfo)309 bool HapSigningBlockUtils::FindHapSubSigningBlock(RandomAccessFile& hapFile, int blockCount,
310     long long blockArrayLen, long long hapSignBlockOffset, SignatureInfo& signInfo)
311 {
312     long long offsetMax = hapSignBlockOffset + blockArrayLen;
313     long long readLen = 0;
314     long long readHeadOffset = hapSignBlockOffset;
315     HAPVERIFY_LOG_DEBUG(LABEL, "hapSignBlockOffset %{public}lld blockArrayLen: %{public}lld blockCount: %{public}d",
316         hapSignBlockOffset, blockArrayLen, blockCount);
317     for (int i = 0; i < blockCount; i++) {
318         HapSubSignBlockHead subSignBlockHead;
319         long long ret = hapFile.ReadFileFullyFromOffset(reinterpret_cast<char*>(&subSignBlockHead),
320             readHeadOffset, sizeof(HapSubSignBlockHead));
321         if (ret < 0) {
322             HAPVERIFY_LOG_ERROR(LABEL, "read %{public}dst subblock head error: %{public}lld", i, ret);
323             return false;
324         }
325         readLen += sizeof(HapSubSignBlockHead);
326 
327         readHeadOffset += sizeof(HapSubSignBlockHead);
328         if (readHeadOffset > offsetMax) {
329             HAPVERIFY_LOG_ERROR(LABEL, "find %{public}dst next head offset error", i);
330             return false;
331         }
332 
333         long long headOffset = static_cast<long long>(subSignBlockHead.offset);
334         long long headLength = static_cast<long long>(subSignBlockHead.length);
335         /* check subSignBlockHead */
336         if ((offsetMax - headOffset) < hapSignBlockOffset) {
337             HAPVERIFY_LOG_ERROR(LABEL, "Find %{public}dst subblock data offset error", i);
338             return false;
339         }
340         if ((blockArrayLen - headLength) < readLen) {
341             HAPVERIFY_LOG_ERROR(LABEL, "no enough data to be read for %{public}dst subblock", i);
342             return false;
343         }
344 
345         long long dataOffset = hapSignBlockOffset + headOffset;
346         HapByteBuffer signBuffer(subSignBlockHead.length);
347         ret = hapFile.ReadFileFullyFromOffset(signBuffer, dataOffset);
348         if (ret < 0) {
349             HAPVERIFY_LOG_ERROR(LABEL, "read %{public}dst subblock error: %{public}lld", i, ret);
350             return false;
351         }
352         readLen += headLength;
353 
354         if (!ClassifyHapSubSigningBlock(signInfo, signBuffer, subSignBlockHead.type)) {
355             HAPVERIFY_LOG_ERROR(LABEL, "ClassifyHapSubSigningBlock error, type is %{public}d",
356                 subSignBlockHead.type);
357             return false;
358         }
359     }
360 
361     /* size of block must be equal to the sum of all subblocks length */
362     if (readLen != blockArrayLen) {
363         HAPVERIFY_LOG_ERROR(LABEL, "readLen: %{public}lld is not same as blockArrayLen: %{public}lld",
364             readLen, blockArrayLen);
365         return false;
366     }
367     return true;
368 }
369 
ClassifyHapSubSigningBlock(SignatureInfo & signInfo,const HapByteBuffer & subBlock,unsigned int type)370 bool HapSigningBlockUtils::ClassifyHapSubSigningBlock(SignatureInfo& signInfo,
371     const HapByteBuffer& subBlock, unsigned int type)
372 {
373     bool ret = false;
374     switch (type) {
375         case HAP_SIGN_BLOB: {
376             if (signInfo.hapSignatureBlock.GetCapacity() != 0) {
377                 HAPVERIFY_LOG_ERROR(LABEL, "find more than one hap sign block");
378                 break;
379             }
380             signInfo.hapSignatureBlock = subBlock;
381             ret = true;
382             break;
383         }
384         case PROFILE_BLOB:
385         case PROOF_ROTATION_BLOB:
386         case PROPERTY_BLOB: {
387             OptionalBlock optionalBlock;
388             optionalBlock.optionalType = static_cast<int>(type);
389             optionalBlock.optionalBlockValue = subBlock;
390             signInfo.optionBlocks.push_back(optionalBlock);
391             ret = true;
392             break;
393         }
394         default:
395             break;
396     }
397     return ret;
398 }
399 
GetOptionalBlockIndex(std::vector<OptionalBlock> & optionBlocks,int type,int & index)400 bool HapSigningBlockUtils::GetOptionalBlockIndex(std::vector<OptionalBlock>& optionBlocks, int type, int& index)
401 {
402     int len = static_cast<int>(optionBlocks.size());
403     for (int i = 0; i < len; i++) {
404         if (optionBlocks[i].optionalType == type) {
405             index = i;
406             return true;
407         }
408     }
409     return false;
410 }
411 
VerifyHapIntegrity(Pkcs7Context & digestInfo,RandomAccessFile & hapFile,SignatureInfo & signInfo)412 bool HapSigningBlockUtils::VerifyHapIntegrity(
413     Pkcs7Context& digestInfo, RandomAccessFile& hapFile, SignatureInfo& signInfo)
414 {
415     if (!SetUnsignedInt32(signInfo.hapEocd, ZIP_CD_OFFSET_IN_EOCD, signInfo.hapSigningBlockOffset)) {
416         HAPVERIFY_LOG_ERROR(LABEL, "Set central dir offset failed");
417         return false;
418     }
419 
420     long long centralDirSize = signInfo.hapEocdOffset - signInfo.hapCentralDirOffset;
421     HapFileDataSource contentsZip(hapFile, 0, signInfo.hapSigningBlockOffset, 0);
422     HapFileDataSource centralDir(hapFile, signInfo.hapCentralDirOffset, centralDirSize, 0);
423     HapByteBufferDataSource eocd(signInfo.hapEocd);
424     DataSource* content[ZIP_BLOCKS_NUM_NEED_DIGEST] = { &contentsZip, &centralDir, &eocd };
425     int nId = HapVerifyOpensslUtils::GetDigestAlgorithmId(digestInfo.digestAlgorithm);
426     DigestParameter digestParam = GetDigestParameter(nId);
427     HapByteBuffer chunkDigest;
428     if (!ComputeDigestsForEachChunk(digestParam, content, ZIP_BLOCKS_NUM_NEED_DIGEST, chunkDigest)) {
429         HAPVERIFY_LOG_ERROR(LABEL, "Compute Content Digests failed, alg: %{public}d", nId);
430         return false;
431     }
432 
433     HapByteBuffer actualDigest;
434     if (!ComputeDigestsWithOptionalBlock(digestParam, signInfo.optionBlocks, chunkDigest, actualDigest)) {
435         HAPVERIFY_LOG_ERROR(LABEL, "Compute Final Digests failed, alg: %{public}d", nId);
436         return false;
437     }
438 
439     if (!digestInfo.content.IsEqual(actualDigest)) {
440         HAPVERIFY_LOG_ERROR(LABEL, "digest of contents verify failed, alg %{public}d", nId);
441         return false;
442     }
443     return true;
444 }
445 
ComputeDigestsWithOptionalBlock(const DigestParameter & digestParam,const std::vector<OptionalBlock> & optionalBlocks,const HapByteBuffer & chunkDigest,HapByteBuffer & finalDigest)446 bool HapSigningBlockUtils::ComputeDigestsWithOptionalBlock(const DigestParameter& digestParam,
447     const std::vector<OptionalBlock>& optionalBlocks, const HapByteBuffer& chunkDigest, HapByteBuffer& finalDigest)
448 {
449     unsigned char out[EVP_MAX_MD_SIZE];
450     int digestLen = HapVerifyOpensslUtils::GetDigest(chunkDigest, optionalBlocks, digestParam, out);
451     if (digestLen != digestParam.digestOutputSizeBytes) {
452         HAPVERIFY_LOG_ERROR(LABEL, "GetDigest failed, outLen is not right, %{public}u, %{public}d",
453             digestLen, digestParam.digestOutputSizeBytes);
454         return false;
455     }
456 
457     finalDigest.SetCapacity(digestParam.digestOutputSizeBytes);
458     finalDigest.PutData(0, reinterpret_cast<char*>(out), digestParam.digestOutputSizeBytes);
459     return true;
460 }
461 
GetSumOfChunkDigestLen(DataSource * contents[],int len,int chunkDigestLen,int & chunkCount,int & sumOfChunkDigestLen)462 bool HapSigningBlockUtils::GetSumOfChunkDigestLen(DataSource* contents[], int len,
463     int chunkDigestLen, int& chunkCount, int& sumOfChunkDigestLen)
464 {
465     for (int i = 0; i < len; i++) {
466         if (contents[i] == nullptr) {
467             HAPVERIFY_LOG_ERROR(LABEL, "contents[%{public}d] is nullptr", i);
468             return false;
469         }
470         contents[i]->Reset();
471         chunkCount += GetChunkCount(contents[i]->Remaining(), CHUNK_SIZE);
472     }
473 
474     if (chunkCount <= 0) {
475         HAPVERIFY_LOG_ERROR(LABEL, "no content for digest");
476         return false;
477     }
478 
479     if (chunkDigestLen < 0 || ((INT_MAX - ZIP_CHUNK_DIGEST_PRIFIX_LEN) / chunkCount) < chunkDigestLen) {
480         HAPVERIFY_LOG_ERROR(LABEL, "overflow chunkCount: %{public}d, chunkDigestLen: %{public}d",
481             chunkCount, chunkDigestLen);
482         return false;
483     }
484 
485     sumOfChunkDigestLen = ZIP_CHUNK_DIGEST_PRIFIX_LEN + chunkCount * chunkDigestLen;
486     return true;
487 }
488 
ComputeDigestsForEachChunk(const DigestParameter & digestParam,DataSource * contents[],int len,HapByteBuffer & result)489 bool HapSigningBlockUtils::ComputeDigestsForEachChunk(const DigestParameter& digestParam,
490     DataSource* contents[], int len, HapByteBuffer& result)
491 {
492     int chunkCount = 0;
493     int sumOfChunksLen = 0;
494     if (!GetSumOfChunkDigestLen(contents, len, digestParam.digestOutputSizeBytes, chunkCount, sumOfChunksLen)) {
495         HAPVERIFY_LOG_ERROR(LABEL, "GetSumOfChunkDigestLen failed");
496         return false;
497     }
498     result.SetCapacity(sumOfChunksLen);
499     result.PutByte(0, ZIP_FIRST_LEVEL_CHUNK_PREFIX);
500     result.PutInt32(1, chunkCount);
501 
502     int chunkIndex = 0;
503     unsigned char out[EVP_MAX_MD_SIZE];
504     unsigned char chunkContentPrefix[ZIP_CHUNK_DIGEST_PRIFIX_LEN] = {ZIP_SECOND_LEVEL_CHUNK_PREFIX, 0, 0, 0, 0};
505     int offset = ZIP_CHUNK_DIGEST_PRIFIX_LEN;
506     for (int i = 0; i < len; i++) {
507         while (contents[i]->HasRemaining()) {
508             int chunkSize = std::min(contents[i]->Remaining(), CHUNK_SIZE);
509             if (!InitDigestPrefix(digestParam, chunkContentPrefix, chunkSize)) {
510                 HAPVERIFY_LOG_ERROR(LABEL, "InitDigestPrefix failed");
511                 return false;
512             }
513 
514             if (!contents[i]->ReadDataAndDigestUpdate(digestParam, chunkSize)) {
515                 HAPVERIFY_LOG_ERROR(LABEL, "Copy Partial Buffer failed, count: %{public}d", chunkIndex);
516                 return false;
517             }
518 
519             int digestLen = HapVerifyOpensslUtils::GetDigest(digestParam, out);
520             if (digestLen != digestParam.digestOutputSizeBytes) {
521                 HAPVERIFY_LOG_ERROR(LABEL, "GetDigest failed len: %{public}d digestSizeBytes: %{public}d",
522                     digestLen, digestParam.digestOutputSizeBytes);
523                 return false;
524             }
525             result.PutData(offset, reinterpret_cast<char*>(out), digestParam.digestOutputSizeBytes);
526             offset += digestLen;
527             chunkIndex++;
528         }
529     }
530     return true;
531 }
532 
GetDigestParameter(int nId)533 DigestParameter HapSigningBlockUtils::GetDigestParameter(int nId)
534 {
535     DigestParameter digestParam;
536     digestParam.digestOutputSizeBytes = HapVerifyOpensslUtils::GetDigestAlgorithmOutputSizeBytes(nId);
537     digestParam.md = EVP_get_digestbynid(nId);
538     digestParam.ptrCtx = EVP_MD_CTX_create();
539     EVP_MD_CTX_init(digestParam.ptrCtx);
540     return digestParam;
541 }
542 
GetChunkCount(long long inputSize,long long chunkSize)543 int HapSigningBlockUtils::GetChunkCount(long long inputSize, long long chunkSize)
544 {
545     if (chunkSize <= 0 || inputSize > LLONG_MAX - chunkSize) {
546         return 0;
547     }
548 
549     long long res = (inputSize + chunkSize - 1) / chunkSize;
550     if (res > INT_MAX || res < 0) {
551         return 0;
552     }
553     return static_cast<int>(res);
554 }
555 
InitDigestPrefix(const DigestParameter & digestParam,unsigned char (& chunkContentPrefix)[ZIP_CHUNK_DIGEST_PRIFIX_LEN],int chunkLen)556 bool HapSigningBlockUtils::InitDigestPrefix(const DigestParameter& digestParam,
557     unsigned char (&chunkContentPrefix)[ZIP_CHUNK_DIGEST_PRIFIX_LEN], int chunkLen)
558 {
559     if (memcpy_s((chunkContentPrefix + 1), ZIP_CHUNK_DIGEST_PRIFIX_LEN - 1, (&chunkLen), sizeof(chunkLen)) != EOK) {
560         HAPVERIFY_LOG_ERROR(LABEL, "memcpy_s failed");
561         return false;
562     }
563 
564     if (!HapVerifyOpensslUtils::DigestInit(digestParam)) {
565         HAPVERIFY_LOG_ERROR(LABEL, "DigestInit failed");
566         return false;
567     }
568 
569     if (!HapVerifyOpensslUtils::DigestUpdate(digestParam, chunkContentPrefix, ZIP_CHUNK_DIGEST_PRIFIX_LEN)) {
570         HAPVERIFY_LOG_ERROR(LABEL, "DigestUpdate failed");
571         return false;
572     }
573     return true;
574 }
575 } // namespace Verify
576 } // namespace Security
577 } // namespace OHOS
578 
579