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