diff --git a/interfaces/innerkits/appverify/include/util/hap_signing_block_utils.h b/interfaces/innerkits/appverify/include/util/hap_signing_block_utils.h index 53959ecccd630c2008e343663d4d0ca2f180840e..d5c44b040f07880aaec2d2cef25af943d1a84e5e 100644 --- a/interfaces/innerkits/appverify/include/util/hap_signing_block_utils.h +++ b/interfaces/innerkits/appverify/include/util/hap_signing_block_utils.h @@ -76,6 +76,8 @@ private: static const int32_t ZIP_BLOCKS_NUM_NEED_DIGEST; static const char ZIP_FIRST_LEVEL_CHUNK_PREFIX; static const char ZIP_SECOND_LEVEL_CHUNK_PREFIX; + static const int32_t ZIP_UPDATE_DIGEST_THREADS_NUM; + static const long long SMALL_FILE_SIZE; /* the specifications of hap sign block */ static constexpr long long MAX_HAP_SIGN_BLOCK_SIZE = 1024 * 1024 * 1024LL; // 1024MB static constexpr int32_t MAX_BLOCK_COUNT = 10; @@ -98,8 +100,14 @@ private: DLL_EXPORT static bool ComputeDigestsWithOptionalBlock(const DigestParameter& digestParam, const std::vector& optionalBlocks, const HapByteBuffer& chunkDigest, HapByteBuffer& finalDigest); - static bool ComputeDigestsForEachChunk(const DigestParameter& digestParam, DataSource* contents[], - int32_t len, HapByteBuffer& result); + static bool ComputeDigestsForDataSourceArray(const DigestParameter& digestParam, DataSource* contents[], + int32_t len, HapByteBuffer& result, const int32_t offset); + static bool ComputeDigestsForDataSource(const DigestParameter& digestParam, DataSource* content, + HapByteBuffer& result, int32_t& offset); + static bool ComputeDigestsForContentsZip(int32_t nId, RandomAccessFile& hapFile, + int32_t chunkNum, long long fileSize, HapByteBuffer& digestsBuffer); + static bool VerifyDigest(const DigestParameter& digestParam, const int32_t nId, + const std::vector& optionalBlocks, const HapByteBuffer& chunkDigest, Pkcs7Context& digestInfo); static int32_t GetChunkCount(long long inputSize, long long chunkSize); static bool InitDigestPrefix(const DigestParameter& digestParam, unsigned char (&chunkContentPrefix)[ZIP_CHUNK_DIGEST_PRIFIX_LEN], int32_t chunkLen); diff --git a/interfaces/innerkits/appverify/src/util/hap_signing_block_utils.cpp b/interfaces/innerkits/appverify/src/util/hap_signing_block_utils.cpp index b8b4d8bb5d3ae4128090cd0e9eecd16143ff806c..150ac7a2c11f5fdd19e562c3d2849f5c61e25627 100644 --- a/interfaces/innerkits/appverify/src/util/hap_signing_block_utils.cpp +++ b/interfaces/innerkits/appverify/src/util/hap_signing_block_utils.cpp @@ -16,6 +16,7 @@ #include "util/hap_signing_block_utils.h" #include +#include #include #include "algorithm" @@ -36,6 +37,7 @@ const long long HapSigningBlockUtils::HAP_SIG_BLOCK_MAGIC_HIGH = 449779798307046 /* 1MB = 1024 * 1024 Bytes */ const long long HapSigningBlockUtils::CHUNK_SIZE = 1048576LL; +const long long HapSigningBlockUtils::SMALL_FILE_SIZE = CHUNK_SIZE * 2; const int32_t HapSigningBlockUtils::HAP_SIG_BLOCK_MIN_SIZE = 32; const int32_t HapSigningBlockUtils::ZIP_HEAD_OF_SIGNING_BLOCK_LENGTH = 32; @@ -46,6 +48,7 @@ const int32_t HapSigningBlockUtils::ZIP_EOCD_COMMENT_LENGTH_OFFSET = 20; const int32_t HapSigningBlockUtils::ZIP_CD_OFFSET_IN_EOCD = 16; const int32_t HapSigningBlockUtils::ZIP_CD_SIZE_OFFSET_IN_EOCD = 12; const int32_t HapSigningBlockUtils::ZIP_BLOCKS_NUM_NEED_DIGEST = 3; +const int32_t HapSigningBlockUtils::ZIP_UPDATE_DIGEST_THREADS_NUM = 4; const char HapSigningBlockUtils::ZIP_FIRST_LEVEL_CHUNK_PREFIX = 0x5a; const char HapSigningBlockUtils::ZIP_SECOND_LEVEL_CHUNK_PREFIX = 0xa5; @@ -428,21 +431,56 @@ bool HapSigningBlockUtils::VerifyHapIntegrity( return false; } + long long contentsZipSize = signInfo.hapSigningBlockOffset; long long centralDirSize = signInfo.hapEocdOffset - signInfo.hapCentralDirOffset; - HapFileDataSource contentsZip(hapFile, 0, signInfo.hapSigningBlockOffset, 0); + HapFileDataSource contentsZip(hapFile, 0, contentsZipSize, 0); HapFileDataSource centralDir(hapFile, signInfo.hapCentralDirOffset, centralDirSize, 0); HapByteBufferDataSource eocd(signInfo.hapEocd); DataSource* content[ZIP_BLOCKS_NUM_NEED_DIGEST] = { &contentsZip, ¢ralDir, &eocd }; int32_t nId = HapVerifyOpensslUtils::GetDigestAlgorithmId(digestInfo.digestAlgorithm); DigestParameter digestParam = GetDigestParameter(nId); HapByteBuffer chunkDigest; - if (!ComputeDigestsForEachChunk(digestParam, content, ZIP_BLOCKS_NUM_NEED_DIGEST, chunkDigest)) { - HAPVERIFY_LOG_ERROR("Compute Content Digests failed, alg: %{public}d", nId); + int32_t chunkCount = 0; + int32_t sumOfChunksLen = 0; + if (!GetSumOfChunkDigestLen(content, ZIP_BLOCKS_NUM_NEED_DIGEST, digestParam.digestOutputSizeBytes, + chunkCount, sumOfChunksLen)) { + HAPVERIFY_LOG_ERROR("GetSumOfChunkDigestLen failed"); return false; } + chunkDigest.SetCapacity(sumOfChunksLen); + chunkDigest.PutByte(0, ZIP_FIRST_LEVEL_CHUNK_PREFIX); + chunkDigest.PutInt32(1, chunkCount); + if (contentsZipSize <= SMALL_FILE_SIZE) { + // No parallel for small size <= 2MB. + int32_t offset = ZIP_CHUNK_DIGEST_PRIFIX_LEN; + if (!ComputeDigestsForDataSourceArray(digestParam, content, ZIP_BLOCKS_NUM_NEED_DIGEST, chunkDigest, offset)) { + HAPVERIFY_LOG_ERROR("Compute Content Digests failed, alg: %{public}d", nId); + return false; + } + } else { + // Compute digests for contents zip in parallel. + int32_t contentsZipChunkCount = GetChunkCount(contentsZipSize, CHUNK_SIZE); + if (!ComputeDigestsForContentsZip(nId, hapFile, contentsZipChunkCount, contentsZipSize, chunkDigest)) { + HAPVERIFY_LOG_ERROR("ComputeDigestsForContentsZip failed, alg: %{public}d", nId); + return false; + } + // Compute digests for other contents. + int32_t offset = ZIP_CHUNK_DIGEST_PRIFIX_LEN + contentsZipChunkCount * digestParam.digestOutputSizeBytes; + if (!ComputeDigestsForDataSourceArray(digestParam, content + 1, + ZIP_BLOCKS_NUM_NEED_DIGEST - 1, chunkDigest, offset)) { + HAPVERIFY_LOG_ERROR("Compute Content Digests failed, alg: %{public}d", nId); + return false; + } + } + + return VerifyDigest(digestParam, nId, signInfo.optionBlocks, chunkDigest, digestInfo); +} +bool HapSigningBlockUtils::VerifyDigest(const DigestParameter& digestParam, const int32_t nId, + const std::vector& optionalBlocks, const HapByteBuffer& chunkDigest, Pkcs7Context& digestInfo) +{ HapByteBuffer actualDigest; - if (!ComputeDigestsWithOptionalBlock(digestParam, signInfo.optionBlocks, chunkDigest, actualDigest)) { + if (!ComputeDigestsWithOptionalBlock(digestParam, optionalBlocks, chunkDigest, actualDigest)) { HAPVERIFY_LOG_ERROR("Compute Final Digests failed, alg: %{public}d", nId); return false; } @@ -497,45 +535,79 @@ bool HapSigningBlockUtils::GetSumOfChunkDigestLen(DataSource* contents[], int32_ return true; } -bool HapSigningBlockUtils::ComputeDigestsForEachChunk(const DigestParameter& digestParam, - DataSource* contents[], int32_t len, HapByteBuffer& result) +bool HapSigningBlockUtils::ComputeDigestsForContentsZip(int32_t nId, RandomAccessFile& hapFile, int32_t chunkNum, + long long contentsZipSize, HapByteBuffer& digestsBuffer) { - int32_t chunkCount = 0; - int32_t sumOfChunksLen = 0; - if (!GetSumOfChunkDigestLen(contents, len, digestParam.digestOutputSizeBytes, chunkCount, sumOfChunksLen)) { - HAPVERIFY_LOG_ERROR("GetSumOfChunkDigestLen failed"); - return false; + int32_t chunkNumToUpdate = (chunkNum + ZIP_UPDATE_DIGEST_THREADS_NUM - 1) / ZIP_UPDATE_DIGEST_THREADS_NUM; + int32_t offset = ZIP_CHUNK_DIGEST_PRIFIX_LEN; + std::vector threads; + std::vector results(ZIP_UPDATE_DIGEST_THREADS_NUM, false); + for (int32_t i = 0; i < ZIP_UPDATE_DIGEST_THREADS_NUM; i++) { + threads.emplace_back([&, i, chunkNumToUpdate, contentsZipSize]() { + long long fileBeginPosition = CHUNK_SIZE * chunkNumToUpdate * i; + long long fileEndPosition = std::min(CHUNK_SIZE * chunkNumToUpdate * (i + 1), contentsZipSize); + long long fileSize = fileEndPosition - fileBeginPosition; + if(fileSize < 0) { + results[i] = true; + return; + } + HapFileDataSource hapDataChunk(hapFile, fileBeginPosition, fileSize, 0); + DigestParameter digestParam = GetDigestParameter(nId); + int32_t digestOffset = offset + chunkNumToUpdate * digestParam.digestOutputSizeBytes * i; + results[i] = ComputeDigestsForDataSource(digestParam, &hapDataChunk, digestsBuffer, digestOffset); + }); + } + + for (auto& thread : threads) { + thread.join(); } - result.SetCapacity(sumOfChunksLen); - result.PutByte(0, ZIP_FIRST_LEVEL_CHUNK_PREFIX); - result.PutInt32(1, chunkCount); - int32_t chunkIndex = 0; + for (bool computeDigestResult : results) { + if (!computeDigestResult) { + HAPVERIFY_LOG_ERROR("Compute digests failed"); + return false; + } + } + + return true; +} + +bool HapSigningBlockUtils::ComputeDigestsForDataSource(const DigestParameter& digestParam, DataSource* content, + HapByteBuffer& result, int32_t& offset) +{ unsigned char out[EVP_MAX_MD_SIZE]; unsigned char chunkContentPrefix[ZIP_CHUNK_DIGEST_PRIFIX_LEN] = {ZIP_SECOND_LEVEL_CHUNK_PREFIX, 0, 0, 0, 0}; - int32_t offset = ZIP_CHUNK_DIGEST_PRIFIX_LEN; - for (int32_t i = 0; i < len; i++) { - while (contents[i]->HasRemaining()) { - int32_t chunkSize = std::min(contents[i]->Remaining(), CHUNK_SIZE); - if (!InitDigestPrefix(digestParam, chunkContentPrefix, chunkSize)) { - HAPVERIFY_LOG_ERROR("InitDigestPrefix failed"); - return false; - } + while (content->HasRemaining()) { + int32_t chunkSize = std::min(content->Remaining(), CHUNK_SIZE); + if (!InitDigestPrefix(digestParam, chunkContentPrefix, chunkSize)) { + HAPVERIFY_LOG_ERROR("InitDigestPrefix failed"); + return false; + } - if (!contents[i]->ReadDataAndDigestUpdate(digestParam, chunkSize)) { - HAPVERIFY_LOG_ERROR("Copy Partial Buffer failed, count: %{public}d", chunkIndex); - return false; - } + if (!content->ReadDataAndDigestUpdate(digestParam, chunkSize)) { + HAPVERIFY_LOG_ERROR("Copy Partial Buffer failed"); + return false; + } - int32_t digestLen = HapVerifyOpensslUtils::GetDigest(digestParam, out); - if (digestLen != digestParam.digestOutputSizeBytes) { - HAPVERIFY_LOG_ERROR("GetDigest failed len: %{public}d digestSizeBytes: %{public}d", - digestLen, digestParam.digestOutputSizeBytes); - return false; - } - result.PutData(offset, reinterpret_cast(out), digestParam.digestOutputSizeBytes); - offset += digestLen; - chunkIndex++; + int32_t digestLen = HapVerifyOpensslUtils::GetDigest(digestParam, out); + if (digestLen != digestParam.digestOutputSizeBytes) { + HAPVERIFY_LOG_ERROR("GetDigest failed len: %{public}d digestSizeBytes: %{public}d", + digestLen, digestParam.digestOutputSizeBytes); + return false; + } + result.PutData(offset, reinterpret_cast(out), digestParam.digestOutputSizeBytes); + offset += digestLen; + } + return true; +} + +bool HapSigningBlockUtils::ComputeDigestsForDataSourceArray(const DigestParameter& digestParam, + DataSource* contents[], int32_t len, HapByteBuffer& result, int32_t offset) +{ + for (int32_t i = 0; i < len; i++) { + if (!ComputeDigestsForDataSource(digestParam, contents[i], result, offset)) { + HAPVERIFY_LOG_ERROR("Compute digest failed"); + return false; } } return true; diff --git a/interfaces/innerkits/appverify/test/unittest/include/hap_signing_block_utils_test.h b/interfaces/innerkits/appverify/test/unittest/include/hap_signing_block_utils_test.h index 74b60c3fdcebebcd9759fb2d5928d71ea94091de..9b4a77c2915c021c6e95b2e193151a30b6728f0b 100644 --- a/interfaces/innerkits/appverify/test/unittest/include/hap_signing_block_utils_test.h +++ b/interfaces/innerkits/appverify/test/unittest/include/hap_signing_block_utils_test.h @@ -26,7 +26,7 @@ namespace OHOS { namespace Security { namespace Verify { -long long CreatTestZipFile(const std::string& pathFile, SignatureInfo& signInfo); +long long CreatTestZipFile(const std::string& pathFile, SignatureInfo& signInfo, const int32_t fileSize); } } } diff --git a/interfaces/innerkits/appverify/test/unittest/include/test_const.h b/interfaces/innerkits/appverify/test/unittest/include/test_const.h index f033fcbac25f49b1c2f39b741a643d719cea4327..c2eebc1c18d7bf0e78a6c102396977149909debd 100644 --- a/interfaces/innerkits/appverify/test/unittest/include/test_const.h +++ b/interfaces/innerkits/appverify/test/unittest/include/test_const.h @@ -40,6 +40,8 @@ constexpr int32_t TEST_HAPBYTEBUFFER_POSITION = 10; constexpr int32_t TEST_HAPBYTEBUFFER_UINT16_LENGTH = 2; constexpr int32_t TEST_HAPBYTEBUFFER_INT64_LENGTH = 8; +// large file size 3MB +constexpr int32_t TEST_LARGE_FILE_BLOCK_LENGTH = 3 * 1048576; constexpr int32_t TEST_FILE_BLOCK_LENGTH = 50; constexpr int32_t TEST_FILE_BLOCK_COUNT = 3; diff --git a/interfaces/innerkits/appverify/test/unittest/src/hap_signing_block_utils_test.cpp b/interfaces/innerkits/appverify/test/unittest/src/hap_signing_block_utils_test.cpp index 6bf6dc07ebdde89aaa3ff666771679d14d925eec..c4daa8161461d2d96b4ca8a6f1a2b882015946b2 100644 --- a/interfaces/innerkits/appverify/test/unittest/src/hap_signing_block_utils_test.cpp +++ b/interfaces/innerkits/appverify/test/unittest/src/hap_signing_block_utils_test.cpp @@ -19,6 +19,7 @@ #include #include +#include #include "common/hap_byte_buffer_data_source.h" #include "common/random_access_file.h" @@ -30,27 +31,31 @@ using namespace OHOS::Security::Verify; namespace OHOS { namespace Security { namespace Verify { -void CreateHapSubSignBlockHead(HapSubSignBlockHead& signBlob, HapSubSignBlockHead& profileBlob, - HapSubSignBlockHead& propertyBlob) +void CreateHapSubSignBlockHead(HapSubSignBlockHead& signBlob, HapSubSignBlockHead& profileBlob, + HapSubSignBlockHead& propertyBlob, const int32_t fileSize) { signBlob.type = HAP_SIGN_BLOB; - signBlob.length = TEST_FILE_BLOCK_LENGTH; + signBlob.length = fileSize; signBlob.offset = sizeof(HapSubSignBlockHead) * TEST_FILE_BLOCK_COUNT; profileBlob.type = PROFILE_BLOB; - profileBlob.length = TEST_FILE_BLOCK_LENGTH; + profileBlob.length = fileSize; profileBlob.offset = signBlob.offset + signBlob.length; propertyBlob.type = PROPERTY_BLOB; - propertyBlob.length = TEST_FILE_BLOCK_LENGTH; + propertyBlob.length = fileSize; propertyBlob.offset = profileBlob.offset + profileBlob.length; } -long long CreatTestZipFile(const std::string& pathFile, SignatureInfo& signInfo) +long long CreatTestZipFile(const std::string& pathFile, SignatureInfo& signInfo, const int32_t fileSize) { std::ofstream hapFile(pathFile.c_str(), std::ios::binary | std::ios::out | std::ios::trunc); if (!hapFile.is_open()) { return 0; } - char block[TEST_FILE_BLOCK_LENGTH] = {0}; + + char block[fileSize]; + if(memset_s(block, fileSize, 0, fileSize) != 0) { + return 0; + } /* input contents of ZIP entries */ hapFile.seekp(0, std::ios_base::beg); hapFile.write(block, sizeof(block)); @@ -58,7 +63,7 @@ long long CreatTestZipFile(const std::string& pathFile, SignatureInfo& signInfo) HapSubSignBlockHead signBlob; HapSubSignBlockHead profileBlob; HapSubSignBlockHead propertyBlob; - CreateHapSubSignBlockHead(signBlob, profileBlob, propertyBlob); + CreateHapSubSignBlockHead(signBlob, profileBlob, propertyBlob, fileSize); hapFile.write(reinterpret_cast(&signBlob), sizeof(signBlob)); hapFile.write(reinterpret_cast(&profileBlob), sizeof(profileBlob)); hapFile.write(reinterpret_cast(&propertyBlob), sizeof(propertyBlob)); @@ -84,14 +89,14 @@ long long CreatTestZipFile(const std::string& pathFile, SignatureInfo& signInfo) hapFile.write(reinterpret_cast(&magic), sizeof(magic)); uint32_t centralDirLen = sizeof(block); hapFile.write(reinterpret_cast(¢ralDirLen), sizeof(centralDirLen)); - uint32_t centralDirOffset = TEST_FILE_BLOCK_LENGTH + signBlockSize; + uint32_t centralDirOffset = fileSize + signBlockSize; hapFile.write(reinterpret_cast(¢ralDirOffset), sizeof(centralDirOffset)); short eocdCommentLen = 0; hapFile.write(reinterpret_cast(&eocdCommentLen), sizeof(eocdCommentLen)); hapFile.close(); signInfo.hapCentralDirOffset = centralDirOffset; signInfo.hapEocdOffset = centralDirOffset + centralDirLen; - signInfo.hapSignatureBlock.SetCapacity(TEST_FILE_BLOCK_LENGTH); + signInfo.hapSignatureBlock.SetCapacity(fileSize); signInfo.hapSignatureBlock.PutData(0, block, sizeof(block)); long long sumLen = signInfo.hapEocdOffset + sizeof(zidEocdSign) + sizeof(centralDirLen) + sizeof(centralDirOffset) + sizeof(magic) + sizeof(eocdCommentLen); @@ -145,7 +150,7 @@ HWTEST_F(HapSigningBlockUtilsTest, FindHapSignatureTest001, TestSize.Level1) */ std::string pathFile = "./test_hapverify.hap"; SignatureInfo signInfo; - int32_t sumLen = CreatTestZipFile(pathFile, signInfo); + int32_t sumLen = CreatTestZipFile(pathFile, signInfo, TEST_FILE_BLOCK_LENGTH); /* * @tc.steps: step2. test FindHapSignature function * @tc.expected: step2. the return will be true. @@ -204,7 +209,7 @@ HWTEST_F(HapSigningBlockUtilsTest, VerifyHapIntegrityTest001, TestSize.Level1) */ std::string pathFile = "./test_hapverify.hap"; SignatureInfo signInfo; - CreatTestZipFile(pathFile, signInfo); + CreatTestZipFile(pathFile, signInfo, TEST_FILE_BLOCK_LENGTH); /* * @tc.steps: step2. create an error digest to test VerifyHapIntegrity function * @tc.expected: step2. the return will be false. @@ -222,6 +227,19 @@ HWTEST_F(HapSigningBlockUtilsTest, VerifyHapIntegrityTest001, TestSize.Level1) RandomAccessFile hapTestFile1; hapTestFile.Init(pathFile); ASSERT_FALSE(hapSignBlockUtils.VerifyHapIntegrity(digestInfo1, hapTestFile1, signInfo)); + + /* + * @tc.steps: step3. create a larger file and an error digest to test VerifyHapIntegrity + * @tc.expected: step3. the return will be false. + */ + std::string pathFile2 = "./test_hapverify2.hap"; + SignatureInfo signInfo2; + CreatTestZipFile(pathFile2, signInfo2, TEST_LARGE_FILE_BLOCK_LENGTH); + Pkcs7Context digestInfo2; + digestInfo2.content.SetCapacity(TEST_LARGE_FILE_BLOCK_LENGTH); + RandomAccessFile hapTestFile2; + hapTestFile2.Init(pathFile2); + ASSERT_FALSE(hapSignBlockUtils.VerifyHapIntegrity(digestInfo2, hapTestFile2, signInfo2)); } /** diff --git a/interfaces/innerkits/appverify/test/unittest/src/random_access_file_test.cpp b/interfaces/innerkits/appverify/test/unittest/src/random_access_file_test.cpp index d62afc0958c415a0517f5e9a4d9ff95912f1d6f5..eab705c2b7a29d4dc9fba15f2ba4508062ea2d68 100644 --- a/interfaces/innerkits/appverify/test/unittest/src/random_access_file_test.cpp +++ b/interfaces/innerkits/appverify/test/unittest/src/random_access_file_test.cpp @@ -72,7 +72,7 @@ HWTEST_F(RandomAccessFileTest, ReadFileFullyFromOffsetTest001, TestSize.Level1) */ std::string filePath = "./test_hapverify.zip"; SignatureInfo si0; - int32_t sumLen = CreatTestZipFile(filePath, si0); + int32_t sumLen = CreatTestZipFile(filePath, si0, TEST_FILE_BLOCK_LENGTH); RandomAccessFile hapTestFile1; bool initRet = hapTestFile1.Init(filePath); ASSERT_TRUE(initRet); @@ -101,7 +101,7 @@ HWTEST_F(RandomAccessFileTest, ReadFileFullyFromOffsetTest001, TestSize.Level1) */ std::string testFile = "./test_hapverify.txt"; SignatureInfo si; - sumLen = CreatTestZipFile(testFile, si); + sumLen = CreatTestZipFile(testFile, si, TEST_FILE_BLOCK_LENGTH); RandomAccessFile hapTestFile2; initRet = hapTestFile2.Init(testFile); ASSERT_TRUE(initRet);