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, ¢ralDir, &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