diff --git a/bundle.json b/bundle.json index 96d327677eb2998a0f21e3622f2c6f1795614757..13d83d2f72efc266e3da3e47cd43b6e4ae1f13ba 100644 --- a/bundle.json +++ b/bundle.json @@ -34,7 +34,8 @@ "eventhandler", "build_framework", "access_token", - "ylong_json" + "ylong_json", + "appverify" ], "third_party": [ "openssl", diff --git a/code_signature.gni b/code_signature.gni index b1f26e5d11d05d602d9e0fccbda27a11ff3f357d..5e5b3effb666bc9016c6f53715a7667da2424eff 100644 --- a/code_signature.gni +++ b/code_signature.gni @@ -17,3 +17,4 @@ fsverity_utils_dir = "//third_party/fsverity-utils" openssl_dir = "//third_party/openssl" rust_openssl_dir = "//third_party/rust/crates/rust-openssl" googletest_dir = "//third_party/googletest" +third_party_securec_dir = "//third_party/bounds_checking_function" diff --git a/interfaces/innerkits/code_sign_utils/BUILD.gn b/interfaces/innerkits/code_sign_utils/BUILD.gn index fc3bdd7e6deed8fd2350cf687727d0e74e4cf7f4..5d6f60ecd2762faac71dd82bf93e495a0d6ef30c 100644 --- a/interfaces/innerkits/code_sign_utils/BUILD.gn +++ b/interfaces/innerkits/code_sign_utils/BUILD.gn @@ -20,6 +20,7 @@ config("public_code_sign_utils_configs") { ohos_shared_library("libcode_sign_utils") { sources = [ + "${code_signature_root_dir}/utils/src/code_sign_block.cpp", "${code_signature_root_dir}/utils/src/file_helper.cpp", "src/code_sign_utils.cpp", "src/stat_utils.cpp", @@ -37,6 +38,7 @@ ohos_shared_library("libcode_sign_utils") { external_deps = [ "ability_base:extractortool", + "appverify:libhapverify", "c_utils:utils", "hilog:libhilog", "hisysevent:libhisysevent", diff --git a/interfaces/innerkits/code_sign_utils/include/code_sign_utils.h b/interfaces/innerkits/code_sign_utils/include/code_sign_utils.h index edce4d7ac3d3ef46daf0b6dbf931b6fc2a84ec43..395169ac2ebb199e6c1c7b60d0140c6b2664e478 100644 --- a/interfaces/innerkits/code_sign_utils/include/code_sign_utils.h +++ b/interfaces/innerkits/code_sign_utils/include/code_sign_utils.h @@ -21,6 +21,7 @@ #include #include #include +#include #include "byte_buffer.h" #include "errcode.h" @@ -29,6 +30,13 @@ namespace Security { namespace CodeSign { using EntryMap = std::unordered_map; +typedef enum { + FILE_ALL, + FILE_SELF, + FILE_ENTRY_ONLY, + FILE_TYPE_MAX, +} FileType; + class CodeSignUtils { public: /** @@ -38,6 +46,16 @@ public: * @return err code, see err_code.h */ static int32_t EnforceCodeSignForApp(const EntryMap &entryPath, const std::string &signatureFile); + + /** + * @brief Enforce code signature for app + * @param path hap real path on disk + * @param entryPath map from entryname in hap to real path on disk + * @param type signature file type + * @return err code, see err_code.h + */ + static int32_t EnforceCodeSignForApp(const std::string &path, const EntryMap &entryPathMap, FileType type); + /** * @brief Enforce code signature for file with signature * @param path file path @@ -46,6 +64,7 @@ public: * @return err code, see err_code.h */ static int32_t EnforceCodeSignForFile(const std::string &path, const uint8_t *signature, const uint32_t len); + /** * @brief Enforce code signature for file with signature * @param path file path @@ -63,8 +82,10 @@ public: private: static int32_t IsSupportFsVerity(const std::string &path); static int32_t IsFsVerityEnabled(int fd); + static int32_t EnableCodeSignForFile(const std::string &path, const struct code_sign_enable_arg &arg); + static void ShowCodeSignInfo(const std::string &path, const struct code_sign_enable_arg &arg); }; } } } -#endif \ No newline at end of file +#endif diff --git a/interfaces/innerkits/code_sign_utils/src/code_sign_utils.cpp b/interfaces/innerkits/code_sign_utils/src/code_sign_utils.cpp index 4afe366845c484929c2c27517dba1e87a09b3163..6064956f5e87abe6beed9538f113876eff039384 100644 --- a/interfaces/innerkits/code_sign_utils/src/code_sign_utils.cpp +++ b/interfaces/innerkits/code_sign_utils/src/code_sign_utils.cpp @@ -37,6 +37,7 @@ #include "log.h" #include "stat_utils.h" #include "signer_info.h" +#include "code_sign_block.h" namespace OHOS { namespace Security { @@ -139,26 +140,17 @@ int32_t CodeSignUtils::EnforceCodeSignForFile(const std::string &path, const Byt return EnforceCodeSignForFile(path, signature.GetBuffer(), signature.GetSize()); } -int32_t CodeSignUtils::EnforceCodeSignForFile(const std::string &path, const uint8_t *signature, - const uint32_t size) +int32_t CodeSignUtils::EnableCodeSignForFile(const std::string &path, const struct code_sign_enable_arg &arg) { - LOG_INFO(LABEL, "Start to enforce"); - if ((signature == nullptr) || (size == 0)) { - return CS_ERR_NO_SIGNATURE; - } - - std::string realPath; - NOT_SATISFIED_RETURN(OHOS::PathToRealPath(path, realPath), CS_ERR_FILE_PATH, - "Get real path failed, path = %{public}s", path.c_str()); - - int fd = open(realPath.c_str(), O_RDONLY); + int32_t ret; + int32_t error; + int32_t fd = open(path.c_str(), O_RDONLY); if (fd < 0) { LOG_ERROR(LABEL, "Open file failed, path = %{public}s, errno = <%{public}d, %{public}s>", - realPath.c_str(), errno, strerror(errno)); + path.c_str(), errno, strerror(errno)); return CS_ERR_FILE_OPEN; } - int32_t ret; do { ret = IsFsVerityEnabled(fd); if (ret == CS_SUCCESS) { @@ -168,17 +160,12 @@ int32_t CodeSignUtils::EnforceCodeSignForFile(const std::string &path, const uin break; } - struct fsverity_enable_arg arg = {}; - arg.version = 1; // version of fs-verity, must be 1 - arg.hash_algorithm = DEFAULT_HASH_ALGORITHEM; - arg.block_size = HASH_PAGE_SIZE; - arg.salt_ptr = 0; - arg.salt_size = 0; - arg.sig_size = size; - arg.sig_ptr = reinterpret_cast(signature); - StartTrace(HITRACE_TAG_ACCESS_CONTROL, CODE_SIGN_ENABLE_START); - int error = ioctl(fd, FS_IOC_ENABLE_VERITY, &arg); + if (!arg.cs_version) { + error = ioctl(fd, FS_IOC_ENABLE_VERITY, &arg); + } else { + error = ioctl(fd, FS_IOC_ENABLE_CODE_SIGN, &arg); + } FinishTrace(HITRACE_TAG_ACCESS_CONTROL); if (error < 0) { LOG_ERROR(LABEL, "Enable fs-verity failed, errno = <%{public}d, %{public}s>", @@ -198,6 +185,91 @@ int CodeSignUtils::ParseOwnerIdFromSignature(const ByteBuffer &sigbuffer, std::s { return SignerInfo::ParseOwnerIdFromSignature(sigbuffer, ownerID); } + +int32_t CodeSignUtils::EnforceCodeSignForFile(const std::string &path, const uint8_t *signature, + const uint32_t size) +{ + std::string realPath; + + if (signature == nullptr || size == 0) { + return CS_ERR_NO_SIGNATURE; + } + if (!OHOS::PathToRealPath(path, realPath)) { + return CS_ERR_FILE_PATH; + } + + struct code_sign_enable_arg arg = {0}; + arg.version = 1; // version of fs-verity, must be 1 + arg.hash_algorithm = DEFAULT_HASH_ALGORITHEM; + arg.block_size = HASH_PAGE_SIZE; + arg.sig_size = size; + arg.sig_ptr = reinterpret_cast(signature); + return EnableCodeSignForFile(realPath, arg); +} + +void CodeSignUtils::ShowCodeSignInfo(const std::string &path, const struct code_sign_enable_arg &arg) +{ + uint8_t *salt = reinterpret_cast(arg.salt_ptr); + uint8_t rootHash[64] = {0}; + uint8_t *rootHashPtr = rootHash; + if (arg.flags & CodeSignBlock::CSB_SIGN_INFO_MERKLE_TREE) { + rootHashPtr = reinterpret_cast(arg.root_hash_ptr); + } + + LOG_DEBUG(LABEL, "{ " + "file:%{public}s version:%{public}d hash_algorithm:%{public}d block_size:%{public}d sig_size:%{public}d " + "data_size:%{public}lld salt_size:%{public}d salt:[%{public}d, ..., %{public}d, ..., %{public}d] " + "flags:%{public}d tree_offset:%{public}lld root_hash:[%{public}d, %{public}d, %{public}d, ..., %{public}d, " + "..., %{public}d] }", + path.c_str(), arg.cs_version, arg.hash_algorithm, arg.block_size, arg.sig_size, + arg.data_size, arg.salt_size, salt[0], salt[16], salt[31], arg.flags, arg.tree_offset, // 16, 31 data index + rootHashPtr[0], rootHashPtr[1], rootHashPtr[2], rootHashPtr[32], rootHashPtr[63]); // 2, 32, 63 data index +} + +int32_t CodeSignUtils::EnforceCodeSignForApp(const std::string &path, const EntryMap &entryPathMap, FileType type) +{ + int32_t ret; + std::string realPath; + + if (!OHOS::PathToRealPath(path, realPath)) { + return CS_ERR_FILE_PATH; + } + + if (type >= FILE_TYPE_MAX) { + return CS_ERR_PARAM_INVALID; + } + + ret = IsSupportFsVerity(realPath); + if (ret != CS_SUCCESS) { + return ret; + } + + CodeSignBlock codeSignBlock; + ret = codeSignBlock.ParseCodeSignBlock(realPath, entryPathMap, type); + if (ret != CS_SUCCESS) { + return ret; + } + + do { + std::string targetFile; + struct code_sign_enable_arg arg = {0}; + ret = codeSignBlock.GetOneFileAndCodeSignInfo(targetFile, arg); + if (ret == CS_SUCCESS_END) { + ret = CS_SUCCESS; + break; + } else if (ret != CS_SUCCESS) { + return ret; + } + + ShowCodeSignInfo(targetFile, arg); + + if (!CheckFilePathValid(targetFile, Constants::ENABLE_APP_BASE_PATH)) { + return CS_ERR_TARGET_FILE_PATH; + } + ret = EnableCodeSignForFile(targetFile, arg); + } while (ret == CS_SUCCESS); + return ret; +} } } } diff --git a/interfaces/innerkits/common/include/errcode.h b/interfaces/innerkits/common/include/errcode.h index 023a5abb8a810da2f1380c4422f9e0a43e7788c1..f6d18dda0fd5e2d2e25d1efe98eaf625e271f436 100644 --- a/interfaces/innerkits/common/include/errcode.h +++ b/interfaces/innerkits/common/include/errcode.h @@ -68,7 +68,35 @@ enum IPCErrCode { CS_ERR_SA_LOAD_FAILED = -0x506, CS_ERR_SA_LOAD_TIMEOUT = -0x507 }; + +enum SignBlockErrCode { + CS_SUCCESS_END = 1, + CS_ERR_BLOCK_MAGIC = -0x600, + CS_ERR_BLOCK_VERSION = -0x601, + CS_ERR_BLOCK_SEG_NUM = -0x602, + CS_ERR_BLOCK_SIZE = -0x603, + CS_ERR_SEGMENT_FSVERITY_TYPE = -0x604, + CS_ERR_SEGMENT_HAP_TYPE = -0x605, + CS_ERR_SEGMENT_SO_TYPE = -0x606, + CS_ERR_SEGMENT_FSVERITY_OFFSET = -0x607, + CS_ERR_SEGMENT_HAP_OFFSET = -0x608, + CS_ERR_SEGMENT_SO_OFFSET = -0x609, + CS_ERR_FSVERITY_MAGIC = -0x610, + CS_ERR_FSVERITY_VERSION = -0x611, + CS_ERR_FSVERITY_BLOCK_SIZE = 0x612, + CS_ERR_HAP_MAGIC = -0x613, + CS_ERR_HAP_EXTERNSION = -0x614, + CS_ERR_SO_MAGIC = -0x615, + CS_ERR_SO_SECTION_NUM = -0x616, + CS_ERR_SO_FILE_OFFSET = -0x617, + CS_ERR_SO_FILE_SIZE = -0x618, + CS_ERR_SO_SIGN_OFFSET = -0x619, + CS_ERR_SO_SIGN_SIZE = -0x620, + CS_ERR_SIGN_ADDR_ALIGN = -0x621, + CS_ERR_SIGN_EXTENSION_OFFSET_ALIGN = -0x622, + CS_ERR_TARGET_FILE_PATH = -0x623, +}; } } } -#endif \ No newline at end of file +#endif diff --git a/test/unittest/BUILD.gn b/test/unittest/BUILD.gn index 69f1daf7a5c72ba4c2fc54caeb15aed1ae23e8dd..d4d216af80aea12b66ade7d2003a867666c48af7 100644 --- a/test/unittest/BUILD.gn +++ b/test/unittest/BUILD.gn @@ -33,9 +33,11 @@ ohos_unittest("code_sign_utils_unittest") { include_dirs = [ "${code_signature_root_dir}/interfaces/innerkits/code_sign_utils/include", + "${code_signature_root_dir}/utils/include", ] external_deps = [ + "appverify:libhapverify", "c_utils:utils", "hilog:libhilog", ] diff --git a/test/unittest/code_sign_utils_test.cpp b/test/unittest/code_sign_utils_test.cpp index 329a3d26ccceaad8372b74463f69aa42fa278dd8..f54d8f3ef55d04ef8eebf49a8484b8948dc58a8b 100644 --- a/test/unittest/code_sign_utils_test.cpp +++ b/test/unittest/code_sign_utils_test.cpp @@ -22,6 +22,7 @@ #include #include "code_sign_utils.h" +#include "code_sign_block.h" namespace OHOS { namespace Security { @@ -42,6 +43,7 @@ struct cert_chain_info { static const uint32_t MAX_CERT_CHAIN = 3; static const std::string TMP_BASE_PATH = "/data/service/el1/public/bms/bundle_manager_service/tmp"; +static const std::string TEST_APP_DTAT_DIR = "/data/app/el1/bundle/public/com.example.codesignaturetest"; static const std::string APP_BASE_PATH = "/data/app/el1/bundle/public/tmp"; static const string DEV_NAME = "/dev/code_sign"; static const string SUBJECT = "Huawei: HarmonyOS Application Code Signature"; @@ -381,6 +383,110 @@ HWTEST_F(CodeSignUtilsTest, CodeSignUtilsTest_0013, TestSize.Level0) int ret = CodeSignUtils::ParseOwnerIdFromSignature(buffer, ownerID); EXPECT_EQ(ret, CS_ERR_OPENSSL_PKCS7); } + +/** + * @tc.name: CodeSignUtilsTest_0014 + * @tc.desc: Parse code signature for hap successfully + * @tc.type: Func + * @tc.require: + */ +HWTEST_F(CodeSignUtilsTest, CodeSignUtilsTest_0014, TestSize.Level0) +{ + std::string hapRealPath = APP_BASE_PATH + "/demo_with_multi_lib/demo_with_code_sign_block.hap"; + EntryMap entryMap; + + CodeSignBlock codeSignBlock; + int32_t ret = codeSignBlock.ParseCodeSignBlock(hapRealPath, entryMap, FILE_SELF); + EXPECT_EQ(ret, CS_SUCCESS); + + std::string targetFile; + struct code_sign_enable_arg arg = {0}; + + ret = codeSignBlock.GetOneFileAndCodeSignInfo(targetFile, arg); + EXPECT_EQ(ret, CS_SUCCESS); + EXPECT_EQ(arg.version, 1); + EXPECT_EQ(arg.cs_version, 1); + EXPECT_EQ(arg.hash_algorithm, 1); + EXPECT_EQ(arg.block_size, 0x1000); + EXPECT_EQ(arg.sig_size, 0x862); + EXPECT_EQ(arg.data_size, 0x5000); + EXPECT_EQ(arg.salt_size, 0); + EXPECT_EQ(arg.flags, 1); + EXPECT_EQ(arg.tree_offset, 0x10c000); + + ret = codeSignBlock.GetOneFileAndCodeSignInfo(targetFile, arg); + EXPECT_EQ(ret, CS_SUCCESS_END); +} + +/** + * @tc.name: CodeSignUtilsTest_0015 + * @tc.desc: parse code signature for native libs successfully + * @tc.type: Func + * @tc.require: + */ +HWTEST_F(CodeSignUtilsTest, CodeSignUtilsTest_0015, TestSize.Level0) +{ + std::string hapRealPath = APP_BASE_PATH + "/demo_with_multi_lib/demo_with_code_sign_block.hap"; + EntryMap entryMap; + std::string filePath1("libs/arm64-v8a/libc++_shared.so"); + std::string targetPath1 = TEST_APP_DTAT_DIR + "libs/arm64/libc++_shared.so"; + entryMap.emplace(filePath1, targetPath1); + std::string filePath2("libs/arm64-v8a/libentry.so"); + std::string targetPath2 = TEST_APP_DTAT_DIR + "libs/arm64/libentry.so"; + entryMap.emplace(filePath2, targetPath2); + + CodeSignBlock codeSignBlock; + int32_t ret = codeSignBlock.ParseCodeSignBlock(hapRealPath, entryMap, FILE_ENTRY_ONLY); + EXPECT_EQ(ret, CS_SUCCESS); + + int32_t count = 0; + do { + std::string targetFile; + struct code_sign_enable_arg arg = {0}; + ret = codeSignBlock.GetOneFileAndCodeSignInfo(targetFile, arg); + if (ret != CS_SUCCESS_END) { + EXPECT_EQ(ret, CS_SUCCESS); + EXPECT_EQ(arg.version, 1); + EXPECT_EQ(arg.cs_version, 1); + EXPECT_EQ(arg.hash_algorithm, 1); + EXPECT_EQ(arg.block_size, 0x1000); + EXPECT_EQ(arg.salt_size, 0); + EXPECT_EQ(arg.flags, 0); + EXPECT_EQ(arg.tree_offset, 0); + count++; + continue; + } + } while (ret == CS_SUCCESS); + EXPECT_EQ(count, 0x2); +} + +/** + * @tc.name: CodeSignUtilsTest_0016 + * @tc.desc: enable code signature for app + * @tc.type: Func + * @tc.require: + */ +HWTEST_F(CodeSignUtilsTest, CodeSignUtilsTest_0016, TestSize.Level0) +{ + std::string hapRealPath = APP_BASE_PATH + "/demo_with_multi_lib/demo_with_code_sign_block.hap"; + EntryMap entryMap; + + int32_t ret = CodeSignUtils::EnforceCodeSignForApp(hapRealPath, entryMap, FILE_SELF); + EXPECT_EQ(ret, CS_SUCCESS); + + std::string filePath1("libs/arm64-v8a/libc++_shared.so"); + std::string targetPath1 = TEST_APP_DTAT_DIR + "libs/arm64/libc++_shared.so"; + entryMap.emplace(filePath1, targetPath1); + std::string filePath2("libs/arm64-v8a/libentry.so"); + std::string targetPath2 = TEST_APP_DTAT_DIR + "libs/arm64/libentry.so"; + entryMap.emplace(filePath2, targetPath2); + + ret = CodeSignUtils::EnforceCodeSignForApp(hapRealPath, entryMap, FILE_ENTRY_ONLY); + EXPECT_EQ(ret, CS_ERR_TARGET_FILE_PATH); + + ret = CodeSignUtils::EnforceCodeSignForApp(hapRealPath, entryMap, FILE_ALL); + EXPECT_EQ(ret, CS_ERR_TARGET_FILE_PATH); +} } // namespace CodeSign } // namespace Security -} // namespace OHOS \ No newline at end of file +} // namespace OHOS diff --git a/test/unittest/resources/demo_with_multi_lib/demo_with_code_sign_block.hap b/test/unittest/resources/demo_with_multi_lib/demo_with_code_sign_block.hap new file mode 100755 index 0000000000000000000000000000000000000000..7aaa672a197bc058d5844bd6412338240e870ac7 Binary files /dev/null and b/test/unittest/resources/demo_with_multi_lib/demo_with_code_sign_block.hap differ diff --git a/test/unittest/resources/ohos_test.xml b/test/unittest/resources/ohos_test.xml index 68ac6c3a36baf0f09765306947fbf6ca55b5e36b..91283bdd624d1a0b226faf8a92fb3e7494a38f7a 100644 --- a/test/unittest/resources/ohos_test.xml +++ b/test/unittest/resources/ohos_test.xml @@ -36,6 +36,7 @@