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, ¢ralDir, &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*>(¢ralDirLen), sizeof(centralDirLen));
647 uint32_t centralDirOffset = TEST_FILE_BLOCK_LENGTH + signBlockSize;
648 hapFileInfo.write(reinterpret_cast<char*>(¢ralDirOffset), 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