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