From c1e6e410a9ddb5bff1206dd467cd74a5e5f17072 Mon Sep 17 00:00:00 2001 From: zfeixiang Date: Tue, 6 May 2025 11:22:52 +0800 Subject: [PATCH] sign elf v2 Signed-off-by: zfeixiang --- binary_sign_tool/BUILD.gn | 101 +++ binary_sign_tool/api/include/service_api.h | 33 + .../api/include/sign_tool_service_impl.h | 39 + .../api/src/sign_tool_service_impl.cpp | 92 ++ binary_sign_tool/cmd/include/cmd_util.h | 51 ++ binary_sign_tool/cmd/include/help.h | 84 ++ binary_sign_tool/cmd/include/params.h | 51 ++ .../cmd/include/params_run_tool.h | 46 + .../cmd/include/params_trust_list.h | 41 + binary_sign_tool/cmd/signature_tools_cmd.gni | 22 + binary_sign_tool/cmd/src/cmd_util.cpp | 430 +++++++++ binary_sign_tool/cmd/src/params.cpp | 68 ++ binary_sign_tool/cmd/src/params_run_tool.cpp | 148 ++++ .../cmd/src/params_trust_list.cpp | 96 ++ binary_sign_tool/common/include/byte_buffer.h | 133 +++ binary_sign_tool/common/include/constant.h | 91 ++ .../common/include/digest_common.h | 64 ++ .../common/include/digest_parameter.h | 38 + .../common/include/export_define.h | 26 + .../common/include/localization_adapter.h | 77 ++ binary_sign_tool/common/include/options.h | 127 +++ .../common/include/pkcs7_context.h | 60 ++ .../common/include/signature_tools_errno.h | 92 ++ .../common/include/signature_tools_log.h | 89 ++ .../common/signature_tools_common.gni | 23 + binary_sign_tool/common/src/byte_buffer.cpp | 642 ++++++++++++++ binary_sign_tool/common/src/digest_common.cpp | 173 ++++ .../common/src/digest_parameter.cpp | 55 ++ .../common/src/localization_adapter.cpp | 324 +++++++ binary_sign_tool/common/src/options.cpp | 158 ++++ .../hap/config/include/signer_config.h | 60 ++ .../hap/config/src/signer_config.cpp | 131 +++ .../hap/entity/include/block_head.h | 42 + .../entity/include/content_digest_algorithm.h | 42 + .../hap/entity/include/param_constants.h | 74 ++ .../include/signature_algorithm_helper.h | 55 ++ .../entity/src/content_digest_algorithm.cpp | 59 ++ .../hap/entity/src/param_constants.cpp | 63 ++ .../entity/src/signature_algorithm_helper.cpp | 71 ++ .../provider/include/local_sign_provider.h | 34 + .../provider/include/remote_sign_provider.h | 34 + .../hap/provider/include/sign_provider.h | 90 ++ .../hap/provider/src/local_sign_provider.cpp | 66 ++ .../hap/provider/src/remote_sign_provider.cpp | 102 +++ .../hap/provider/src/sign_provider.cpp | 445 ++++++++++ .../hap/sign/include/bc_pkcs7_generator.h | 47 + .../hap/sign/include/pkcs7_generator.h | 40 + binary_sign_tool/hap/sign/include/sign_elf.h | 54 ++ .../hap/sign/src/bc_pkcs7_generator.cpp | 105 +++ binary_sign_tool/hap/sign/src/sign_elf.cpp | 199 +++++ binary_sign_tool/hap/signature_tools_hap.gni | 35 + .../hap/utils/include/dynamic_lib_handle.h | 34 + .../hap/utils/include/hap_utils.h | 56 ++ .../hap/utils/src/dynamic_lib_handle.cpp | 30 + .../hap/verify/include/matching_result.h | 38 + binary_sign_tool/main.cpp | 25 + binary_sign_tool/profile/include/pkcs7_data.h | 149 ++++ .../profile/include/profile_info.h | 99 +++ .../profile/include/profile_sign_tool.h | 60 ++ .../profile/include/profile_verify.h | 55 ++ .../profile/signature_tools_profile.gni | 22 + binary_sign_tool/profile/src/pkcs7_data.cpp | 821 ++++++++++++++++++ binary_sign_tool/profile/src/profile_info.cpp | 70 ++ .../profile/src/profile_sign_tool.cpp | 71 ++ .../profile/src/profile_verify.cpp | 293 +++++++ binary_sign_tool/signature_tools.gni | 24 + .../signer/include/local_signer.h | 59 ++ binary_sign_tool/signer/include/signer.h | 37 + .../signer/include/signer_factory.h | 50 ++ binary_sign_tool/signer/src/local_signer.cpp | 106 +++ .../signer/src/signer_factory.cpp | 82 ++ binary_sign_tool/utils/include/file_utils.h | 125 +++ binary_sign_tool/utils/include/hash_utils.h | 54 ++ .../utils/include/key_store_helper.h | 94 ++ .../utils/include/signature_info.h | 29 + binary_sign_tool/utils/include/string_utils.h | 45 + .../utils/include/verify_cert_openssl_utils.h | 62 ++ .../utils/include/verify_hap_openssl_utils.h | 63 ++ .../utils/signature_tools_utils.gni | 23 + binary_sign_tool/utils/src/file_utils.cpp | 363 ++++++++ binary_sign_tool/utils/src/hash_utils.cpp | 154 ++++ .../utils/src/key_store_helper.cpp | 764 ++++++++++++++++ binary_sign_tool/utils/src/string_utils.cpp | 128 +++ .../utils/src/verify_cert_openssl_utils.cpp | 295 +++++++ .../utils/src/verify_hap_openssl_utils.cpp | 255 ++++++ hapsigntool_cpp/bundle.json | 3 + 86 files changed, 9960 insertions(+) create mode 100644 binary_sign_tool/BUILD.gn create mode 100644 binary_sign_tool/api/include/service_api.h create mode 100644 binary_sign_tool/api/include/sign_tool_service_impl.h create mode 100644 binary_sign_tool/api/src/sign_tool_service_impl.cpp create mode 100644 binary_sign_tool/cmd/include/cmd_util.h create mode 100644 binary_sign_tool/cmd/include/help.h create mode 100644 binary_sign_tool/cmd/include/params.h create mode 100644 binary_sign_tool/cmd/include/params_run_tool.h create mode 100644 binary_sign_tool/cmd/include/params_trust_list.h create mode 100644 binary_sign_tool/cmd/signature_tools_cmd.gni create mode 100644 binary_sign_tool/cmd/src/cmd_util.cpp create mode 100644 binary_sign_tool/cmd/src/params.cpp create mode 100644 binary_sign_tool/cmd/src/params_run_tool.cpp create mode 100644 binary_sign_tool/cmd/src/params_trust_list.cpp create mode 100644 binary_sign_tool/common/include/byte_buffer.h create mode 100644 binary_sign_tool/common/include/constant.h create mode 100644 binary_sign_tool/common/include/digest_common.h create mode 100644 binary_sign_tool/common/include/digest_parameter.h create mode 100644 binary_sign_tool/common/include/export_define.h create mode 100644 binary_sign_tool/common/include/localization_adapter.h create mode 100644 binary_sign_tool/common/include/options.h create mode 100644 binary_sign_tool/common/include/pkcs7_context.h create mode 100644 binary_sign_tool/common/include/signature_tools_errno.h create mode 100644 binary_sign_tool/common/include/signature_tools_log.h create mode 100644 binary_sign_tool/common/signature_tools_common.gni create mode 100644 binary_sign_tool/common/src/byte_buffer.cpp create mode 100644 binary_sign_tool/common/src/digest_common.cpp create mode 100644 binary_sign_tool/common/src/digest_parameter.cpp create mode 100644 binary_sign_tool/common/src/localization_adapter.cpp create mode 100644 binary_sign_tool/common/src/options.cpp create mode 100644 binary_sign_tool/hap/config/include/signer_config.h create mode 100644 binary_sign_tool/hap/config/src/signer_config.cpp create mode 100644 binary_sign_tool/hap/entity/include/block_head.h create mode 100644 binary_sign_tool/hap/entity/include/content_digest_algorithm.h create mode 100644 binary_sign_tool/hap/entity/include/param_constants.h create mode 100644 binary_sign_tool/hap/entity/include/signature_algorithm_helper.h create mode 100644 binary_sign_tool/hap/entity/src/content_digest_algorithm.cpp create mode 100644 binary_sign_tool/hap/entity/src/param_constants.cpp create mode 100644 binary_sign_tool/hap/entity/src/signature_algorithm_helper.cpp create mode 100644 binary_sign_tool/hap/provider/include/local_sign_provider.h create mode 100644 binary_sign_tool/hap/provider/include/remote_sign_provider.h create mode 100644 binary_sign_tool/hap/provider/include/sign_provider.h create mode 100644 binary_sign_tool/hap/provider/src/local_sign_provider.cpp create mode 100644 binary_sign_tool/hap/provider/src/remote_sign_provider.cpp create mode 100644 binary_sign_tool/hap/provider/src/sign_provider.cpp create mode 100644 binary_sign_tool/hap/sign/include/bc_pkcs7_generator.h create mode 100644 binary_sign_tool/hap/sign/include/pkcs7_generator.h create mode 100644 binary_sign_tool/hap/sign/include/sign_elf.h create mode 100644 binary_sign_tool/hap/sign/src/bc_pkcs7_generator.cpp create mode 100644 binary_sign_tool/hap/sign/src/sign_elf.cpp create mode 100644 binary_sign_tool/hap/signature_tools_hap.gni create mode 100644 binary_sign_tool/hap/utils/include/dynamic_lib_handle.h create mode 100644 binary_sign_tool/hap/utils/include/hap_utils.h create mode 100644 binary_sign_tool/hap/utils/src/dynamic_lib_handle.cpp create mode 100644 binary_sign_tool/hap/verify/include/matching_result.h create mode 100644 binary_sign_tool/main.cpp create mode 100644 binary_sign_tool/profile/include/pkcs7_data.h create mode 100644 binary_sign_tool/profile/include/profile_info.h create mode 100644 binary_sign_tool/profile/include/profile_sign_tool.h create mode 100644 binary_sign_tool/profile/include/profile_verify.h create mode 100644 binary_sign_tool/profile/signature_tools_profile.gni create mode 100644 binary_sign_tool/profile/src/pkcs7_data.cpp create mode 100644 binary_sign_tool/profile/src/profile_info.cpp create mode 100644 binary_sign_tool/profile/src/profile_sign_tool.cpp create mode 100644 binary_sign_tool/profile/src/profile_verify.cpp create mode 100644 binary_sign_tool/signature_tools.gni create mode 100644 binary_sign_tool/signer/include/local_signer.h create mode 100644 binary_sign_tool/signer/include/signer.h create mode 100644 binary_sign_tool/signer/include/signer_factory.h create mode 100644 binary_sign_tool/signer/src/local_signer.cpp create mode 100644 binary_sign_tool/signer/src/signer_factory.cpp create mode 100644 binary_sign_tool/utils/include/file_utils.h create mode 100644 binary_sign_tool/utils/include/hash_utils.h create mode 100644 binary_sign_tool/utils/include/key_store_helper.h create mode 100644 binary_sign_tool/utils/include/signature_info.h create mode 100644 binary_sign_tool/utils/include/string_utils.h create mode 100644 binary_sign_tool/utils/include/verify_cert_openssl_utils.h create mode 100644 binary_sign_tool/utils/include/verify_hap_openssl_utils.h create mode 100644 binary_sign_tool/utils/signature_tools_utils.gni create mode 100644 binary_sign_tool/utils/src/file_utils.cpp create mode 100644 binary_sign_tool/utils/src/hash_utils.cpp create mode 100644 binary_sign_tool/utils/src/key_store_helper.cpp create mode 100644 binary_sign_tool/utils/src/string_utils.cpp create mode 100644 binary_sign_tool/utils/src/verify_cert_openssl_utils.cpp create mode 100644 binary_sign_tool/utils/src/verify_hap_openssl_utils.cpp diff --git a/binary_sign_tool/BUILD.gn b/binary_sign_tool/BUILD.gn new file mode 100644 index 00000000..04d734d4 --- /dev/null +++ b/binary_sign_tool/BUILD.gn @@ -0,0 +1,101 @@ +# Copyright (c) 2025-2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("cmd/signature_tools_cmd.gni") +# import("codesigning/signature_tools_codesigning.gni") +import("common/signature_tools_common.gni") +import("hap/signature_tools_hap.gni") +import("profile/signature_tools_profile.gni") +import("signature_tools.gni") +import("utils/signature_tools_utils.gni") + +import("//build/ohos.gni") + +ohos_copy("copy_signature_tools_resource") { + sources = [ + "../dist/OpenHarmony.p12", + "../dist/OpenHarmonyApplication.pem", + "../dist/OpenHarmonyProfileDebug.pem", + "../dist/OpenHarmonyProfileRelease.pem", + "../dist/SgnedReleaseProfileTemplate.p7b", + "../dist/UnsgnedDebugProfileTemplate.json", + "../dist/UnsgnedReleasedProfileTemplate.json", + ] + outputs = + [ "${target_out_dir}/toolchains/hapsigntool_pc/{{source_file_part}}" ] + module_source_dir = target_out_dir + "/toolchains/hapsigntool_pc" + module_install_name = "" + part_name = "hapsigner" + subsystem_name = "developtools" +} + +signature_tools_main_include = [ + "${signature_tools_api}/include", + "${signature_tools_signer}/include", + "//third_party/openssl/include", + "//third_party/openssl/crypto/pkcs12", +] + +signature_tools_main_src = [ + "main.cpp", + "${signature_tools_api}/src/sign_tool_service_impl.cpp", + "${signature_tools_signer}/src/signer_factory.cpp", + "${signature_tools_signer}/src/local_signer.cpp", +] + +ohos_executable("binary-sign-tool") { + signature_tools_main_include += signature_tools_utils_include + + # signature_tools_main_include += signature_tools_codesigning_include + signature_tools_main_include += signature_tools_common_include + signature_tools_main_include += signature_tools_hap_include + signature_tools_main_include += signature_tools_profile_include + signature_tools_main_include += signature_tools_cmd_include + + # 在 //developtools/signaturetools/services/utils 模块里面定义编译脚本 signature_tools_utils.gni + signature_tools_main_src += signature_tools_utils_src + # signature_tools_main_src += signature_tools_codesigning_src + signature_tools_main_src += signature_tools_common_src + signature_tools_main_src += signature_tools_hap_src + signature_tools_main_src += signature_tools_profile_src + signature_tools_main_src += signature_tools_cmd_src + + include_dirs = signature_tools_main_include + sources = signature_tools_main_src + + deps = [ + "//third_party/elfio:elfio", + "//third_party/openssl:libcrypto_shared", + "//third_party/openssl:libssl_shared", + ] + + external_deps = [ + "bounds_checking_function:libsec_static", + "json:nlohmann_json_static", + ] + + cflags_cc = [ + "-std=c++17", + "-fno-rtti", + ] + + cflags = [ + "-fno-rtti", + "-Wno-c++20-extensions", + ] + + install_images = [ "system" ] + install_enable = false + part_name = "hapsigner" + subsystem_name = "developtools" +} diff --git a/binary_sign_tool/api/include/service_api.h b/binary_sign_tool/api/include/service_api.h new file mode 100644 index 00000000..0807eda6 --- /dev/null +++ b/binary_sign_tool/api/include/service_api.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGNERTOOLS_SERVICE_API_H +#define SIGNERTOOLS_SERVICE_API_H + +#include "options.h" + +namespace OHOS { +namespace SignatureTools { + +class ServiceApi { +public: + ServiceApi() = default; + ~ServiceApi() = default; + + virtual bool Sign(Options* params) = 0; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNERTOOLS_SERVICE_API_H \ No newline at end of file diff --git a/binary_sign_tool/api/include/sign_tool_service_impl.h b/binary_sign_tool/api/include/sign_tool_service_impl.h new file mode 100644 index 00000000..3520547a --- /dev/null +++ b/binary_sign_tool/api/include/sign_tool_service_impl.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_SIGNTOOLSERVICELMPL_H +#define SIGNATRUETOOLS_SIGNTOOLSERVICELMPL_H + +#include "options.h" +#include "file_utils.h" +#include "localization_adapter.h" +#include "signature_tools_log.h" +#include "service_api.h" + +namespace OHOS { +namespace SignatureTools { + +class SignToolServiceImpl : public ServiceApi { +public: + static int GetProvisionContent(const std::string& input, std::string& ret); + SignToolServiceImpl() = default; + virtual ~SignToolServiceImpl() = default; + bool Sign(Options* options)override; + +private: + bool SignAdHoc(Options* options); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_SIGNTOOLSERVICELMPL_H diff --git a/binary_sign_tool/api/src/sign_tool_service_impl.cpp b/binary_sign_tool/api/src/sign_tool_service_impl.cpp new file mode 100644 index 00000000..3fe16f3d --- /dev/null +++ b/binary_sign_tool/api/src/sign_tool_service_impl.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sign_tool_service_impl.h" +#include "pkcs7_data.h" +#include "profile_sign_tool.h" +#include "nlohmann/json.hpp" +#include "profile_info.h" +#include "profile_verify.h" +#include "signature_tools_errno.h" +#include "local_sign_provider.h" +#include "signature_tools_log.h" +#include "param_constants.h" +#include "constant.h" +#include "remote_sign_provider.h" + +namespace OHOS { +namespace SignatureTools { +bool SignToolServiceImpl::Sign(Options* options) +{ + std::string inFile = options->GetString(Options::IN_FILE); + if (!FileUtils::isElfFile(inFile)) { + SIGNATURE_TOOLS_LOGE("inFile is not a elf file"); + return false; + } + if (options->GetString(Options::AD_HOC) == ParamConstants::AD_HOC_TYPE_1) { + return SignAdHoc(options); + } + std::string mode = options->GetString(Options::MODE); + std::shared_ptr signProvider; + if (LOCAL_SIGN == mode) { + signProvider = std::make_shared(); + } else if (REMOTE_SIGN == mode) { + signProvider = std::make_shared(); + } else { + SIGNATURE_TOOLS_LOGE("Resign mode. But not implemented yet"); + return false; + } + return signProvider->SignElf(options); +} + +int SignToolServiceImpl::GetProvisionContent(const std::string& input, std::string& ret) +{ + std::string bytes; + if (FileUtils::ReadFile(input, bytes) < 0) { + SIGNATURE_TOOLS_LOGE("provision read faild!"); + return IO_ERROR; + } + nlohmann::json obj = nlohmann::json::parse(bytes); + if (obj.is_discarded() || (!obj.is_structured())) { + PrintErrorNumberMsg("PARSE ERROR", PARSE_ERROR, "Parsing provision failed!"); + return PARSE_ERROR; + } + ret = obj.dump(); + ProfileInfo provision; + AppProvisionVerifyResult result = ParseProvision(ret, provision); + if (result != PROVISION_OK) { + SIGNATURE_TOOLS_LOGE("invalid provision"); + return INVALIDPARAM_ERROR; + } + return 0; +} + +bool SignToolServiceImpl::SignAdHoc(Options* options) +{ + std::string inFile = options->GetString(Options::IN_FILE); + std::string outFile = options->GetString(Options::OUT_FILE); + std::string tmpOutFile = outFile; + if (outFile == inFile) { + tmpOutFile = "tmp-signed-elf"; + } + bool ret = std::filesystem::copy_file(inFile, tmpOutFile, std::filesystem::copy_options::overwrite_existing); + if (!ret) { + SIGNATURE_TOOLS_LOGE("Error: SignAdHoc failed"); + return false; + } + return FileUtils::CopyTmpFileAndDel(tmpOutFile, outFile); +} +} // namespace SignatureTools +} // namespace OHOS diff --git a/binary_sign_tool/cmd/include/cmd_util.h b/binary_sign_tool/cmd/include/cmd_util.h new file mode 100644 index 00000000..00e8996d --- /dev/null +++ b/binary_sign_tool/cmd/include/cmd_util.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGNATRUETOOLS_CMD_UTIL_H +#define SIGNATRUETOOLS_CMD_UTIL_H + +#include +#include +#include +#include +#include +#include + +#include "params.h" +#include "params_trust_list.h" +#include "sign_tool_service_impl.h" +#include "signature_tools_log.h" +#include "verify_hap_openssl_utils.h" + +namespace OHOS { +namespace SignatureTools { +class CmdUtil final { +public: + static bool Convert2Params(char** args, const size_t size, const ParamsSharedPtr& param); + static bool JudgeSignAlgType(const std::string& signAlg); + static bool String2Bool(Options* options, const std::string& option); + static bool UpdateParamForCheckInFile(Options* options, const std::initializer_list& inFileKeys); + static bool UpdateParamForCheckOutFile(Options* options, const std::initializer_list& outFileKeys); + static constexpr int ARGS_MIN_LEN = 2; + +private: + static int GetCommandParameterKey(const char strChar, std::string& strChars, + std::vector& trustList, std::string& keyStandBy); + static bool ValidAndPutParam(const ParamsSharedPtr& params, const std::string& key, char* value); + static const std::regex INTEGER_PATTERN; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif diff --git a/binary_sign_tool/cmd/include/help.h b/binary_sign_tool/cmd/include/help.h new file mode 100644 index 00000000..a4b797f0 --- /dev/null +++ b/binary_sign_tool/cmd/include/help.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef HELP_H +#define HELP_H + +#include + /* this file use to create help.txt content and + * it is divided into 12 strings according + * to the functional module + */ +namespace OHOS { +namespace SignatureTools { + +const std::string HELP_TXT_HEADER = R"( +USAGE: [options] +)"; + +const std::string SIGN_APP_HELP_TXT = R"( + sign[options]: + -mode : signature mode, required fields, including localSign/remoteSign/remoteResign; + -keyAlias : key alias, required fields; + -keyPwd : key password, optional fields on localSign mode; + -appCertFile : application signature certificate file, required fields on localSign mode, optional fields + on remoteSign mode; + -profileFile : signed Provision Profile file, p7b format, required fields; + -profileSigned : indicates whether the profile file has a signature.The options are as follows + : 1 : yes; 0:no; default value:1. optional fields; + -inFile : input original application package file, .hap, .bin, and .elf format, required fields; + -signAlg : signature algorithm, required fields, including SHA256withECDSA/SHA384withECDSA; + -keystoreFile : keystore file, if signature mode is localSign, required fields on localSign mode, + JKS or P12 format; + -keystorePwd : keystore password, optional fields on localSign mode; + -outFile : output the signed Provision Profile file, required fields; + application package file format is hap; + -signServer : remote signer plugin, required fields on remoteSign mode; + -signerPlugin : remote sign service url, required fields on remoteSign mode; + -onlineAuthMode : remote sign auth mode, required fields on remoteSign mode, including account; + -username : user account for online auth, required fields on remoteSign mode with account auth mode; + -userPwd : user password for online auth, required fields on remoteSign mode with account auth mode; + -ext : extend parameters for remote signer plugin, optional fields; + -signCode : Whether the HAP file is signed code, The value 1 means enable sign code, and value 0 means + disable sign code.The default value is 1. It is optional. + -moduleFile : module.json file. + -adHoc : Whether the HAP file is ad hoc, The value 1 means enable ad hoc, and value 0 means disable ad hoc. + The default value is 0. It is optional. + + EXAMPLE : + sign -keyAlias "oh-app1-key-v1" -appCertFile "/home/app-release-cert.cer" -signCode "1" +-keystoreFile "/home/app-keypair.jks" -keystorePwd ****** -outFile "/home/app1-signed.hap +-profileFile "/home/signed-profile.p7b" -inFile "/home/app1-unsigned.hap" -signAlg SHA256withECDSA +)"; + +const std::string VERIFY_APP_HELP_TXT = R"( + verify-app[options]: + -inFile : signed application package file, hap or bin format, required fields; + -outCertChain : signed certificate chain file, required fields; + -outProfile : profile file in application package, required fields; + + EXAMPLE: + verify-app-inFile "/home/app1-signed.hap" -outCertChain "outCertChain.cer" -outProfile "outprofile.p7b" +)"; + +const std::string HELP_END_TXT = R"( +COMMANDS : + sign : application package signature + verify-app : application package file verification +)"; +/* help.txt all content */ +const std::string HELP_TXT = HELP_TXT_HEADER + SIGN_APP_HELP_TXT + VERIFY_APP_HELP_TXT + HELP_END_TXT; +} +} +#endif \ No newline at end of file diff --git a/binary_sign_tool/cmd/include/params.h b/binary_sign_tool/cmd/include/params.h new file mode 100644 index 00000000..06cf85b3 --- /dev/null +++ b/binary_sign_tool/cmd/include/params.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGNATRUETOOLS_PARAMS_H +#define SIGNATRUETOOLS_PARAMS_H + +#include +#include +#include +#include +#include +#include + +#include "options.h" +#include "signature_algorithm_helper.h" +#include "param_constants.h" + +namespace OHOS { +namespace SignatureTools { +class Params { +public: + static std::unordered_set InitParamField(const std::vector& paramFields); + static bool GetSignatureAlgorithm(const std::string& signatureAlgorithm, SignatureAlgorithmHelper& out); + Params(); + ~Params(); + std::string GetMethod(); + void SetMethod(const std::string& method); + Options* GetOptions(); + +private: + Options* options; + std::string method; +}; + +using ParamsSharedPtr = std::shared_ptr; + +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_PARAMS_H diff --git a/binary_sign_tool/cmd/include/params_run_tool.h b/binary_sign_tool/cmd/include/params_run_tool.h new file mode 100644 index 00000000..dce33852 --- /dev/null +++ b/binary_sign_tool/cmd/include/params_run_tool.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGNATRUETOOLS_HAP_SIGN_TOOL_H +#define SIGNATRUETOOLS_HAP_SIGN_TOOL_H + +#include +#include +#include + +#include "cmd_util.h" +#include "sign_tool_service_impl.h" +#include "signature_tools_log.h" +#include "params_trust_list.h" +#include "string_utils.h" + +namespace OHOS { +namespace SignatureTools { +class ParamsRunTool final { +public: + ParamsRunTool() = delete; + static bool ProcessCmd(char** args, size_t size); + static bool DispatchParams(const ParamsSharedPtr& params, SignToolServiceImpl& api); + static bool RunSignApp(Options* params, SignToolServiceImpl& api); + static bool CheckProfile(Options& params); + static void PrintHelp(); + static void Version(); + +private: + static const std::string VERSION; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_HAP_SIGN_TOOL_H diff --git a/binary_sign_tool/cmd/include/params_trust_list.h b/binary_sign_tool/cmd/include/params_trust_list.h new file mode 100644 index 00000000..f06416da --- /dev/null +++ b/binary_sign_tool/cmd/include/params_trust_list.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGNATRUETOOLS_PARAMSTRUSTLIST_H +#define SIGNATRUETOOLS_PARAMSTRUSTLIST_H + +#include +#include +#include +#include +#include +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { +class ParamsTrustList final { +public: + static ParamsTrustList GetInstance(); + std::vector GetTrustList(const std::string& command); +private: + void ReadHelpParam(std::istringstream& fd); + void PutTrustMap(const std::string& cmd_stand_by, const std::string& param); + void GenerateTrustList(); +private: + std::unordered_map> trustMap; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif diff --git a/binary_sign_tool/cmd/signature_tools_cmd.gni b/binary_sign_tool/cmd/signature_tools_cmd.gni new file mode 100644 index 00000000..2681dd6a --- /dev/null +++ b/binary_sign_tool/cmd/signature_tools_cmd.gni @@ -0,0 +1,22 @@ +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("../signature_tools.gni") +signature_tools_cmd_include = [ "${signature_tools_cmd}/include" ] + +signature_tools_cmd_src = [ + "${signature_tools_cmd}/src/cmd_util.cpp", + "${signature_tools_cmd}/src/params_run_tool.cpp", + "${signature_tools_cmd}/src/params_trust_list.cpp", + "${signature_tools_cmd}/src/params.cpp", +] diff --git a/binary_sign_tool/cmd/src/cmd_util.cpp b/binary_sign_tool/cmd/src/cmd_util.cpp new file mode 100644 index 00000000..efb9b46b --- /dev/null +++ b/binary_sign_tool/cmd/src/cmd_util.cpp @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "cmd_util.h" +#include +#include + +#include "params_run_tool.h" +#include "constant.h" +#include "param_constants.h" + +namespace OHOS { +namespace SignatureTools { +const std::regex INTEGER_PATTERN = std::regex("\\d{1,10}"); + +bool CmdUtil::String2Bool(Options* options, const std::string& option) +{ + std::string val = options->GetString(option); + if (val == "1" || val == "true" || val == "TRUE") { + (*options)[option] = true; + } else if (val == "0" || val == "false" || val == "FALSE") { + (*options)[option] = false; + } else { + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, + val + " is not valid value for " + "-" + option); + return false; + } + return true; +} + +static bool UpdateParamForVariantCertInt(const ParamsSharedPtr& param) +{ + int defaultValidity = 0; + Options* options = param->GetOptions(); + if (options->count(Options::VALIDITY)) { + int validity = 0; + std::string val = options->GetString(Options::VALIDITY); + for (char x : val) { + if (!isdigit(x)) { + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, "Invalid parameter '" + + val + "', You should fill in the numbers"); + return false; + } + } + if (!StringUtils::CheckStringToint(val, validity)) { + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, "Invalid parameter '" + + val + "'"); + return false; + } + validity *= ONE_DAY_TIME; + (*options)[Options::VALIDITY] = validity; + } else if (param->GetMethod() == GENERATE_CA || param->GetMethod() == GENERATE_APP_CERT || + param->GetMethod() == GENERATE_PROFILE_CERT) { + defaultValidity = DEFAULT_VALIDITY_DAYS * ONE_DAY_TIME; + (*options)[Options::VALIDITY] = defaultValidity; + } else if (param->GetMethod() == GENERATE_CERT) { + defaultValidity = DEFAULT_CUSTOM_VALIDITY_DAYS * ONE_DAY_TIME; + (*options)[Options::VALIDITY] = defaultValidity; + } + return true; +} + +static bool UpdateParamForVariantInt(const ParamsSharedPtr& param) +{ + Options* options = param->GetOptions(); + // general + if (options->count(Options::KEY_SIZE)) { + std::string keySize = options->GetString(Options::KEY_SIZE); + if (keySize == "NIST-P-256") { + (*options)[Options::KEY_SIZE] = NIST_P_256; + } else if (keySize == "NIST-P-384") { + (*options)[Options::KEY_SIZE] = NIST_P_384; + } else { + PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "not supported '" + keySize + + "' Key algorithms length"); + return false; + } + } + if (options->count(Options::BASIC_CONSTRAINTS_PATH_LEN)) { + int basicConstraintsPathLen = 0; + std::string val = options->GetString(Options::BASIC_CONSTRAINTS_PATH_LEN); + if (!StringUtils::CheckStringToint(val, basicConstraintsPathLen)) { + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, "Invalid parameter '" + + val + "', You should fill in the numbers"); + return false; + } + (*options)[Options::BASIC_CONSTRAINTS_PATH_LEN] = basicConstraintsPathLen; + } else if (param->GetMethod() == GENERATE_CA || param->GetMethod() == GENERATE_CERT) { + (*options)[Options::BASIC_CONSTRAINTS_PATH_LEN] = DEFAULT_BASIC_CONSTRAINTS_PATH_LEN; + } + if (!UpdateParamForVariantCertInt(param)) { + return false; + } + return true; +} + +static bool UpdateParamForVariantBoolKeyUsage(const ParamsSharedPtr& param) +{ + Options* options = param->GetOptions(); + + // The bool type is used only by the "generate-cert" module + if (options->count(Options::KEY_USAGE_CRITICAL)) { + if (!CmdUtil::String2Bool(options, Options::KEY_USAGE_CRITICAL)) { + return false; + } + } else if (param->GetMethod() == GENERATE_CERT) { + (*options)[Options::KEY_USAGE_CRITICAL] = DEFAULT_KEY_USAGE_CRITICAL; + } + + // The bool type is used only by the "generate-cert" module + if (options->count(Options::EXT_KEY_USAGE_CRITICAL)) { + if (!CmdUtil::String2Bool(options, Options::EXT_KEY_USAGE_CRITICAL)) { + return false; + } + } else if (param->GetMethod() == GENERATE_CERT) { + (*options)[Options::EXT_KEY_USAGE_CRITICAL] = DEFAULT_EXT_KEY_USAGE_CRITICAL; + } + return true; +} + +static bool UpdateParamForVariantBoolProfileSigned(const ParamsSharedPtr& param) +{ + Options* options = param->GetOptions(); + + // The bool type is used only by the "sign-elf" module + if (options->count(Options::PROFILE_SIGNED)) { + std::string val = options->GetString(Options::PROFILE_SIGNED); + if (val == "1" || val == "true" || val == "TRUE") { + (*options)[Options::PROFILE_SIGNED] = DEFAULT_PROFILE_SIGNED_1; + } else if (val == "0" || val == "false" || val == "FALSE") { + (*options)[Options::PROFILE_SIGNED] = DEFAULT_PROFILE_SIGNED_0; + } else { + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, + val + " is not valid value for "+"-" + Options::PROFILE_SIGNED); + return false; + } + } else if (param->GetMethod() == SIGN_ELF) { + (*options)[Options::PROFILE_SIGNED] = DEFAULT_PROFILE_SIGNED_1; + } + + return true; +} + +static bool UpdateParamForVariantBoolAdHoc(const ParamsSharedPtr& param) +{ + Options* options = param->GetOptions(); + // The bool type is used only by the "sign-elf" module + if (options->count(Options::AD_HOC)) { + std::string val = options->GetString(Options::AD_HOC); + if (val == "1" || val == "true" || val == "TRUE") { + (*options)[Options::AD_HOC] = ParamConstants::AD_HOC_TYPE_1; + } else if (val == "0" || val == "false" || val == "FALSE") { + (*options)[Options::AD_HOC] = ParamConstants::AD_HOC_TYPE_0; + } else { + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, + val + " is not valid value for "+"-" + Options::AD_HOC); + return false; + } + } else if (param->GetMethod() == SIGN_ELF) { + (*options)[Options::AD_HOC] = ParamConstants::AD_HOC_TYPE_0; + } + + return true; +} + +bool CmdUtil::UpdateParamForCheckOutFile(Options* options, const std::initializer_list& outFileKeys) +{ + for (auto& key : outFileKeys) { + if (options->count(key)) { + std::string outFilePath = options->GetString(key); + std::filesystem::path filePath = outFilePath; + std::string parentPath = filePath.parent_path(); + + // Purpose: To prevent the user output path from passing an empty string. eg " " + std::string tmpOutFilePath = outFilePath; + tmpOutFilePath.erase(std::remove_if(tmpOutFilePath.begin(), + tmpOutFilePath.end(), ::isspace), tmpOutFilePath.end()); + + if (parentPath.empty() && !tmpOutFilePath.empty()) { + parentPath = "./"; + } + char realFilePath[PATH_MAX + 1] = {0x00}; + if (parentPath.size() > PATH_MAX) { + PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "'" + outFilePath + "' File path longer than '" + + std::to_string(PATH_MAX) + "' characters"); + return false; + } + if (realpath(parentPath.c_str(), realFilePath) == nullptr) { + PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "The '" + outFilePath + + "' file does not exist or the path is invalid" + + ", parameter name '-" + key + "'"); + return false; + } + std::string charStr(realFilePath); + std::string fileName = filePath.filename(); + if (fileName.empty()) { + PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "The file name cannot be empty '" + + outFilePath + "', parameter name '-" + key + "'"); + return false; + } + (*options)[key] = charStr + "/" + fileName; + } + } + return true; +} + +bool CmdUtil::UpdateParamForCheckInFile(Options* options, const std::initializer_list& inFileKeys) +{ + for (auto& key : inFileKeys) { + if (options->count(key)) { + std::string inFilePath = options->GetString(key); + char realFilePath[PATH_MAX + 1] = {0x00}; + if (inFilePath.size() > PATH_MAX) { + PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "'" + inFilePath + "' File path longer than '" + + std::to_string(PATH_MAX) + "' characters"); + return false; + } + if (realpath(inFilePath.c_str(), realFilePath) == nullptr) { + PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "The '" + inFilePath + + "' file does not exist or the path is invalid" + + ", parameter name '-" + key + "'"); + return false; + } + std::string charStr(realFilePath); + (*options)[key] = charStr; + + if (!FileUtils::IsValidFile(inFilePath)) { + return false; + } + } + } + + return true; +} + +static bool UpdateParamForCheckSignAlg(const ParamsSharedPtr& param) +{ + // check signAlg + Options* options = param->GetOptions(); + if (options->count(Options::SIGN_ALG)) { + std::string signAlg = options->GetString(Options::SIGN_ALG); + if (signAlg != SIGN_ALG_SHA256 && signAlg != SIGN_ALG_SHA384) { + PrintErrorNumberMsg("NOT_SUPPORT_ERROR", NOT_SUPPORT_ERROR, "'" + signAlg + "' parameter is incorrect"); + return false; + } + } + return true; +} + +static bool UpdateParamForOutform(const ParamsSharedPtr& param) +{ + // check generate_app_cert generate_profile_cert + Options* options = param->GetOptions(); + if (param->GetMethod() == GENERATE_APP_CERT || + param->GetMethod() == GENERATE_PROFILE_CERT) { + if (options->count(Options::OUT_FORM)) { + std::string outForm = options->GetString(Options::OUT_FORM); + if (outForm != OUT_FORM_CERT && outForm != OUT_FORM_CERT_CHAIN) { + PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "parameter '" + outForm + + "' format error, Outform only supprot cert/cerChain"); + return false; + } + } else { + (*options)[Options::OUT_FORM] = OUT_FORM_CERT_CHAIN; + } + } + return true; +} + +// Check "remoteSign" additional parameters are required +static bool UpdateParamForCheckRemoteSignProfile(const ParamsSharedPtr& param) +{ + Options* options = param->GetOptions(); + std::set signProfileRemoteParams{ParamConstants::PARAM_REMOTE_SERVER, + ParamConstants::PARAM_REMOTE_USERNAME, + ParamConstants::PARAM_REMOTE_USERPWD, + ParamConstants::PARAM_REMOTE_ONLINEAUTHMODE, + ParamConstants::PARAM_REMOTE_SIGNERPLUGIN}; + + if (param->GetMethod() == SIGN_PROFILE && options->count(Options::MODE) && + options->GetString(Options::MODE) == REMOTE_SIGN) { + for (const std::string& key : signProfileRemoteParams) { + if (options->count(key) == 0) { + PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "sign profile RemoteSign absence param '" + + key + "'"); + return false; + } + } + } + return true; +} + +static bool UpdateParam(const ParamsSharedPtr& param) +{ + if (!UpdateParamForVariantInt(param)) { + return false; + } + if (!UpdateParamForVariantBoolKeyUsage(param)) { + return false; + } + if (!UpdateParamForVariantBoolProfileSigned(param)) { + return false; + } + if (!UpdateParamForVariantBoolAdHoc(param)) { + return false; + } + if (!UpdateParamForCheckSignAlg(param)) { + return false; + } + if (!UpdateParamForOutform(param)) { + return false; + } + if (!UpdateParamForCheckRemoteSignProfile(param)) { + return false; + } + return true; +} + +int CmdUtil::GetCommandParameterKey(const char strChar, std::string& strChars, std::vector& trustList, + std::string& keyStandBy) +{ + if (strChar == '-') { + bool isTrust = std::find(trustList.begin(), trustList.end(), strChars) != trustList.end(); + if (!isTrust) { + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, "There is no '" + + strChars + "' command for the trust list"); + return RET_FAILED; + } + keyStandBy = strChars.substr(1); + } else { + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, "'" + strChars + + "' Parameters error, Param key - value must in pairs"); + return RET_FAILED; + } + + return RET_OK; +} + +bool CmdUtil::Convert2Params(char** args, const size_t size, const ParamsSharedPtr& param) +{ + param->SetMethod(args[1]); + std::string keyStandBy = ""; + bool readKey = true; + std::vector trustList = ParamsTrustList::GetInstance().GetTrustList(args[1]); + if (trustList.empty()) { + return false; + } + std::string strChars; + for (size_t i = 2; i < size; i++) { + if (readKey) { + strChars = args[i]; + if (GetCommandParameterKey(args[i][0], strChars, trustList, keyStandBy) == RET_OK) { + readKey = false; + } else { + return false; + } + } else { + bool success = ValidAndPutParam(param, keyStandBy, args[i]); + if (success) { + keyStandBy = ""; + readKey = true; + } else { + return false; + } + } + } + param->GetOptions()->emplace(Options::MODE, LOCAL_SIGN); + if (!readKey) { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, + "The last value of parameter cannot be omitted"); + return false; + } + if (!UpdateParam(param)) { + return false; + } + return true; +} + +bool CmdUtil::ValidAndPutParam(const ParamsSharedPtr& params, const std::string& key, char* value) +{ + std::string str = "Pwd"; + bool result = true; + if (key.empty()) { + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, + "The command-line parameter key cannot be empty"); + result = false; + } else if (strlen(value) == 0) { + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, + "The command-line parameter value cannot be empty"); + result = false; + } else if (params->GetOptions()->count(key)) { + PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, + "Duplicate command parameter are not allowed '" + key + "'"); + result = false; + } else if (key.length() >= str.length() && key.substr(key.length() - INVALIDCHAR) == str) { + params->GetOptions()->emplace(key, value); + } else { + if (key == Options::KEY_ALIAS || key == Options::ISSUER_KEY_ALIAS) { + std::string keyAlias = value; + std::transform(keyAlias.begin(), keyAlias.end(), keyAlias.begin(), + [](unsigned char c) { return std::tolower(c); }); + params->GetOptions()->emplace(key, keyAlias); + } else { + params->GetOptions()->emplace(key, std::string(value)); + } + } + return result; +} + +bool CmdUtil::JudgeSignAlgType(const std::string& signAlg) +{ + if (signAlg != SIGN_ALG_SHA256 && signAlg != SIGN_ALG_SHA384) { + PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "not supported '" + signAlg + "' signature algorithm"); + return false; + } + return true; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/cmd/src/params.cpp b/binary_sign_tool/cmd/src/params.cpp new file mode 100644 index 00000000..a8c51f83 --- /dev/null +++ b/binary_sign_tool/cmd/src/params.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "params.h" + +namespace OHOS { +namespace SignatureTools { +Params::Params() : options(new Options) { +} + +Params::~Params() +{ + if (options) { + delete options; + options = NULL; + } +} + +std::string Params::GetMethod() +{ + return method; +} + +void Params::SetMethod(const std::string& method) +{ + this->method = method; +} + +Options* Params::GetOptions() +{ + return options; +} + +std::unordered_set Params::InitParamField(const std::vector& paramFields) +{ + return std::unordered_set(paramFields.begin(), paramFields.end()); +} + +bool Params::GetSignatureAlgorithm(const std::string& signatureAlgorithm, + SignatureAlgorithmHelper& out) +{ + if (signatureAlgorithm == ParamConstants::HAP_SIG_ALGORITHM_SHA256_ECDSA) { + out = SignatureAlgorithmHelper::ECDSA_WITH_SHA256_INSTANCE; + return true; + } else if (signatureAlgorithm == ParamConstants::HAP_SIG_ALGORITHM_SHA384_ECDSA) { + out = SignatureAlgorithmHelper::ECDSA_WITH_SHA384_INSTANCE; + return true; + } else { + SIGNATURE_TOOLS_LOGE("get Signature Algorithm failed not support %s", signatureAlgorithm.c_str()); + return false; + } + return true; +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/cmd/src/params_run_tool.cpp b/binary_sign_tool/cmd/src/params_run_tool.cpp new file mode 100644 index 00000000..61727cc4 --- /dev/null +++ b/binary_sign_tool/cmd/src/params_run_tool.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "params_run_tool.h" +#include +#include +#include + +#include "constant.h" +#include "help.h" + +namespace OHOS { +namespace SignatureTools { +const std::string ParamsRunTool::VERSION = "1.0.0"; + +static std::unordered_map > DISPATCH_RUN_METHOD { + {SIGN_ELF, ParamsRunTool::RunSignApp} +}; + +bool ParamsRunTool::ProcessCmd(char** args, size_t size) +{ + if (size < CmdUtil::ARGS_MIN_LEN) { + PrintHelp(); + return true; + } + if (args == nullptr || strcmp(args[1], "") == 0) { + PrintHelp(); + return true; + } else if (strcmp(args[1], "-h") == 0 || strcmp(args[1], "-help") == 0) { + PrintHelp(); + return true; + } else if (strcmp(args[1], "-v") == 0 || strcmp(args[1], "-version") == 0) { + Version(); + return true; + } else { + std::shared_ptr serviceApi = std::make_shared(); + ParamsSharedPtr param = std::make_shared(); + if (!CmdUtil::Convert2Params(args, size, param)) { + PrintMsg(param->GetMethod() + " failed"); + return false; + } + PrintMsg("Start " + param->GetMethod()); + SIGNATURE_TOOLS_LOGD("%s run start time ", param->GetMethod().c_str()); + if (!DispatchParams(param, *serviceApi)) { + SIGNATURE_TOOLS_LOGD("%s run end time ", param->GetMethod().c_str()); + PrintMsg(param->GetMethod() + " failed"); + return false; + } + PrintMsg(param->GetMethod() + " success"); + SIGNATURE_TOOLS_LOGD("%s run end time ", param->GetMethod().c_str()); + } + return true; +} + +bool ParamsRunTool::RunSignApp(Options* params, SignToolServiceImpl& api) +{ + if (!params->Required({Options::MODE, Options::IN_FILE, Options::OUT_FILE})) { + return false; + } + if (!CmdUtil::UpdateParamForCheckInFile(params, {Options::IN_FILE, Options::APP_CERT_FILE, + Options::PROFILE_FILE, Options::KEY_STORE_FILE, Options::MODULE_FILE, + ParamConstants::PARAM_REMOTE_SIGNERPLUGIN})) { + return false; + } + if (!CmdUtil::UpdateParamForCheckOutFile(params, {Options::OUT_FILE})) { + return false; + } + if (params->GetString(Options::AD_HOC) == ParamConstants::AD_HOC_TYPE_1) { + return api.Sign(params); + } + std::string mode = params->GetString(Options::MODE); + if (!StringUtils::CaseCompare(mode, LOCAL_SIGN) && + !StringUtils::CaseCompare(mode, REMOTE_SIGN)) { + PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "not support command param '" + mode + "'"); + return false; + } + if (StringUtils::CaseCompare(mode, LOCAL_SIGN)) { + if (!params->Required({Options::KEY_STORE_FILE, Options::KEY_ALIAS, Options::APP_CERT_FILE})) { + return false; + } + if (!FileUtils::ValidFileType(params->GetString(Options::KEY_STORE_FILE), {"p12", "jks"})) { + return false; + } + } + if (!CheckProfile(*params)) { + return false; + } + std::string signAlg = params->GetString(Options::SIGN_ALG); + if (!CmdUtil::JudgeSignAlgType(signAlg)) { + return false; + } + return api.Sign(params); +} + +bool ParamsRunTool::CheckProfile(Options& params) +{ + std::string profileFile = params.GetString(Options::PROFILE_FILE); + std::string profileSigned = params.GetString(Options::PROFILE_SIGNED); + if (profileSigned == DEFAULT_PROFILE_SIGNED_1) { + if (!FileUtils::ValidFileType(profileFile, {"p7b"})) { + return false; + } + } else { + if (!FileUtils::ValidFileType(profileFile, {"json"})) { + return false; + } + } + return true; +} + +bool ParamsRunTool::DispatchParams(const ParamsSharedPtr& params, SignToolServiceImpl& api) +{ + bool isSuccess = false; + std::string method = params->GetMethod(); + auto it = DISPATCH_RUN_METHOD.find(method); + if (it == DISPATCH_RUN_METHOD.end()) { + PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "Unsupported method: " + method); + return false; + } else { + isSuccess = it->second(params->GetOptions(), api); + } + return isSuccess; +} + +void ParamsRunTool::PrintHelp() +{ + PrintMsg(HELP_TXT); +} + +void ParamsRunTool::Version() +{ + PrintMsg(ParamsRunTool::VERSION); +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/cmd/src/params_trust_list.cpp b/binary_sign_tool/cmd/src/params_trust_list.cpp new file mode 100644 index 00000000..d91f1ab3 --- /dev/null +++ b/binary_sign_tool/cmd/src/params_trust_list.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "params_trust_list.h" +#include + +#include "constant.h" +#include "params.h" +#include "string_utils.h" +#include "help.h" + +namespace OHOS { +namespace SignatureTools { +const std::string options = "[options]:"; + +const std::vector commands = { + SIGN_PROFILE + options, + VERIFY_PROFILE + options, + SIGN_ELF + options, + VERIFY_APP + options +}; + +ParamsTrustList ParamsTrustList::GetInstance() +{ + static ParamsTrustList instance; + return instance; +} + +void ParamsTrustList::PutTrustMap(const std::string& cmdStandBy, const std::string& param) +{ + if (param.at(0) == '-') { + size_t pos = param.find(':'); + std::string subParam = param.substr(0, pos); + subParam = StringUtils::Trim(subParam); + bool isExists = false; + if (trustMap.find(cmdStandBy) != trustMap.end()) { + isExists = true; + } + std::vector trustList = isExists ? trustMap[cmdStandBy] : std::vector(); + trustList.push_back(subParam); + trustMap[cmdStandBy] = trustList; + } +} + +void ParamsTrustList::ReadHelpParam(std::istringstream& fd) +{ + std::string str; + std::string cmdStandBy; + while (std::getline(fd, str)) { + bool isExists = false; + std::string params = StringUtils::Trim(str); + if (params.empty()) { + continue; + } + isExists = std::any_of(commands.begin(), commands.end(), + [params](const std::string& cmd) {return cmd == params; }); + if (isExists) { + cmdStandBy = params; + } else { + PutTrustMap(cmdStandBy, params); + } + } +} + +void ParamsTrustList::GenerateTrustList() +{ + std::istringstream iss(HELP_TXT); + ReadHelpParam(iss); +} + +std::vector ParamsTrustList::GetTrustList(const std::string& command) +{ + std::string keyParam = command + options; + GenerateTrustList(); + if (trustMap.find(keyParam) != trustMap.end()) { + return trustMap[keyParam]; + } else { + PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "'" + command + " is not trust command"); + trustMap[keyParam].clear(); + return trustMap[keyParam]; + } +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/common/include/byte_buffer.h b/binary_sign_tool/common/include/byte_buffer.h new file mode 100644 index 00000000..247aa1c6 --- /dev/null +++ b/binary_sign_tool/common/include/byte_buffer.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_BYTEBUFFER_H +#define SIGNATRUETOOLS_BYTEBUFFER_H + +#include +#include + +#include "export_define.h" + +namespace OHOS { +namespace SignatureTools { + +enum ReadFileErrorCode { + DEST_BUFFER_IS_NULL = -1, + FILE_IS_CLOSE = -2, + MMAP_COPY_FAILED = -3, + READ_OFFSET_OUT_OF_RANGE = -4, + MMAP_FAILED = -5, + MMAP_PARAM_INVALID = -6, +}; +/* +* The underlying storage structure of ByteBuffer is an array, and all operations are based on that array. +* ByteBuffer is in its initial state and also in a write state after creation +* +* 1. Several position related member variables in the ByteBuffer class +* Mark: Read the starting position of the data to facilitate subsequent rollback to that position +* Position: Where to start reading or writing +* Limit: When reading the status, it indicates how much data is actually stored; +* Equal to capacity when writing status +* Capacity: represents the capacity of ByteBuffer, which is the maximum number of bytes that can be stored +* +* Bool hasRemaining(); Is there any data between position and limit +* Uint32_t remaining() const; Return the number of bytes between position and limit +* +* 2. Set ByteBuffer from writer state to read state: limit is set to position value, position is set to zero +* Void flip(); +* +* 3. If you want to write or overwrite again, you can call clear() or compact() +* Void clear()// Reset to initial state: mark=-1, position=0, limit=capacity +* Void compact()// Copy the data between position and limit to the starting position at index 0, +* then move the position to the next position of this data segment and set the limit value to capacity +*/ +class ByteBuffer { +public: + DLL_EXPORT ByteBuffer(); + DLL_EXPORT explicit ByteBuffer(int32_t bufferCapacity); + DLL_EXPORT ByteBuffer(const char* arr, int32_t length); + DLL_EXPORT ByteBuffer(const ByteBuffer& other); + DLL_EXPORT ~ByteBuffer(); + DLL_EXPORT ByteBuffer& operator=(const ByteBuffer& other); + DLL_EXPORT bool GetInt64(int64_t& value); + DLL_EXPORT bool GetInt64(int32_t index, int64_t& value); + DLL_EXPORT bool GetUInt32(uint32_t& value); + DLL_EXPORT bool GetUInt32(int32_t index, uint32_t& value); + DLL_EXPORT bool GetInt32(int32_t& value); + DLL_EXPORT bool GetInt32(int32_t index, int32_t& value); + DLL_EXPORT bool GetUInt16(uint16_t& value); + DLL_EXPORT bool GetUInt16(int32_t index, uint16_t& value); + DLL_EXPORT bool GetInt16(int16_t& value); + DLL_EXPORT bool GetInt16(int32_t index, int16_t& value); + DLL_EXPORT bool GetUInt8(uint8_t& value); + DLL_EXPORT bool GetUInt8(int32_t index, uint8_t& value); + DLL_EXPORT bool GetInt8(int8_t& value); + DLL_EXPORT bool GetInt8(int32_t index, int8_t& value); + DLL_EXPORT void PutUInt8(uint8_t value); + DLL_EXPORT void PutUInt16(uint16_t value); + DLL_EXPORT void PutUInt32(uint32_t value); + DLL_EXPORT void PutInt16(int16_t value); + DLL_EXPORT void PutInt16(int32_t offset, int16_t value); + DLL_EXPORT void PutInt32(int32_t value); + DLL_EXPORT void PutInt32(int32_t offset, int32_t value); + DLL_EXPORT void PutInt64(int64_t value); + DLL_EXPORT void PutByte(int32_t offset, char value); + DLL_EXPORT void PutData(const char data[], int32_t len); + DLL_EXPORT void PutData(int8_t data[], int32_t len); + DLL_EXPORT void PutData(int32_t offset, const char data[], int32_t len); + DLL_EXPORT void PutData(int32_t offset, const int8_t data[], int32_t len); + DLL_EXPORT void PutData(int32_t offset, const char data[], int32_t len, int32_t type); + DLL_EXPORT void PutByte(char value); + DLL_EXPORT void Put(const ByteBuffer& byteBuffer); + DLL_EXPORT void GetData(char data[], uint32_t len); + DLL_EXPORT void GetData(int32_t offset, int8_t data[], uint32_t len); + DLL_EXPORT void GetByte(int8_t data[], int32_t len); + DLL_EXPORT void ClearData(); + DLL_EXPORT int32_t GetCapacity() const; + DLL_EXPORT int32_t GetPosition() const; + DLL_EXPORT int32_t GetLimit() const; + DLL_EXPORT const char* GetBufferPtr() const; + DLL_EXPORT void SetPosition(int32_t pos); + DLL_EXPORT void SetLimit(int32_t lim); + DLL_EXPORT void SetCapacity(int32_t cap); + DLL_EXPORT ByteBuffer& Slice(); + DLL_EXPORT ByteBuffer& slice_for_codesigning(); + DLL_EXPORT ByteBuffer* Duplicate(); + DLL_EXPORT int32_t Remaining() const; + DLL_EXPORT bool HasRemaining() const; + DLL_EXPORT void Clear(); + DLL_EXPORT ByteBuffer& Flip(); + // to the beginning of the cache area; Switch to write state + DLL_EXPORT bool IsEqual(const ByteBuffer& other); + DLL_EXPORT bool IsEqual(const std::string& other); + DLL_EXPORT void Rewind(); + DLL_EXPORT ByteBuffer& RewindHap(); + DLL_EXPORT std::string ToString(); + +private: + void Init(int32_t bufferCapacity); + bool CheckInputForGettingData(int32_t index, int32_t dataLen); + +private: + static const int32_t MAX_PRINT_LENGTH; + static const int32_t HEX_PRINT_LENGTH; + std::shared_ptr buffer; + int32_t position = 0; + int32_t limit = 0; + int32_t capacity = 0; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_BYTEBUFFER_H diff --git a/binary_sign_tool/common/include/constant.h b/binary_sign_tool/common/include/constant.h new file mode 100644 index 00000000..e7154c0d --- /dev/null +++ b/binary_sign_tool/common/include/constant.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGNATRUETOOLS_CONSTANT_H +#define SIGNATRUETOOLS_CONSTANT_H + +#include +#include + +namespace OHOS { +namespace SignatureTools { +const char APP_SIGNING_CAPABILITY[] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x0A, 0x01, 0x00}; +const char PROFILE_SIGNING_CAPABILITY[] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x0A, 0x01, 0x01}; + +constexpr long DEFAULT_START_VALIDITY = 0; +constexpr long ONE_DAY_TIME = 86400; +constexpr long DEFAULT_CERT_VERSION = 2; + +constexpr int NIST_P_256 = 256; +constexpr int NIST_P_384 = 384; +constexpr int DEFAULT_VALIDITY_DAYS = 3650; +constexpr int INVALIDCHAR = 3; +constexpr int DEFAULT_BASIC_CONSTRAINTS_PATH_LEN = 0; +constexpr int RANDOM_SERIAL_NUMBER_LENGTH = 32; +constexpr int DEFAULT_CUSTOM_VALIDITY_DAYS = 1095; + +const bool DEFAULT_KEY_USAGE_CRITICAL = true; +const bool DEFAULT_EXT_KEY_USAGE_CRITICAL = false; +const bool DEFAULT_BASIC_CONSTRAINTS = false; +const bool DEFAULT_BASIC_CONSTRAINTS_CRITICAL = false; +const bool DEFAULT_BASIC_CONSTRAINTS_CA = false; + +const std::string SIGN_ALG_SHA256 = "SHA256withECDSA"; +const std::string SIGN_ALG_SHA384 = "SHA384withECDSA"; +const std::string DEFAULT_BASIC_EXTENSION = "critical,CA:FALSE"; +const std::string DEFAULT_KEYUSAGE_EXTENSION = "digitalSignature"; +const std::string DEFAULT_EXTEND_KEYUSAGE = "codeSigning"; +const std::string NID_BASIC_CONST = "basicConstraints"; +const std::string NID_KEYUSAGE_CONST = "keyUsage"; +const std::string NID_EXT_KEYUSAGE_CONST = "extendedKeyUsage"; +const std::string PKCS7_EXT_SIGNATURE_OID = "1.2.840.113549.1.1.10"; +const std::string X509_EXT_OID = "1.3.6.1.4.1.2011.2.376.1.3"; +const std::string OWNERID_OID = "1.3.6.1.4.1.2011.2.376.1.4.1"; // SIGNED_ID +const std::string OWNERID_OID_SHORT_NAME = "ownerID"; +const std::string OWNERID_OID_LONG_NAME = "Code Signature Owner ID"; +const std::string DEFAULT_PROFILE_SIGNED_1 = "1"; +const std::string DEFAULT_PROFILE_SIGNED_0 = "0"; +const std::string ZIP = "zip"; +const std::string ELF = "elf"; +const std::string BIN = "bin"; +const std::string OUT_FORM_CERT = "cert"; +const std::string OUT_FORM_CERT_CHAIN = "certChain"; +const std::string DEBUG_STR = "debug"; +const std::string DEBUG_LIB_ID = "DEBUG_LIB_ID"; +const std::string REMOTE_SIGN = "remoteSign"; +const std::string LOCAL_SIGN = "localSign"; + +// Corresponding to each functional module +const std::string GENERATE_KEYPAIR = "generate-keypair"; +const std::string GENERATE_CSR = "generate-csr"; +const std::string GENERATE_CA = "generate-ca"; +const std::string GENERATE_CERT = "generate-cert"; +const std::string GENERATE_APP_CERT = "generate-app-cert"; +const std::string GENERATE_PROFILE_CERT = "generate-profile-cert"; +const std::string SIGN_ELF = "sign"; +const std::string SIGN_PROFILE = "sign-profile"; +const std::string VERIFY_APP = "verify-app"; +const std::string VERIFY_PROFILE = "verify-profile"; + +constexpr int32_t ONE_DAY_HOUR = 24; +constexpr int32_t ONE_DAY_MINUTE = 60; +constexpr int32_t ONE_DAY_SECOND = 60; + +static constexpr int YEAR1900 = 1900; +static constexpr int MIN_CERTS_NUM = 2; +static constexpr int MAX_CERTS_NUM = 3; +} // namespace UpdateEngine +} // namespace OHOS +#endif // SIGNATRUETOOLS_CONSTANT_H \ No newline at end of file diff --git a/binary_sign_tool/common/include/digest_common.h b/binary_sign_tool/common/include/digest_common.h new file mode 100644 index 00000000..20f7645c --- /dev/null +++ b/binary_sign_tool/common/include/digest_common.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_DIGESTCOMMON_H +#define SIGNATRUETOOLS_DIGESTCOMMON_H +#include +#include + +#include "byte_buffer.h" +#include "openssl/evp.h" +#include "openssl/ossl_typ.h" +#include "digest_parameter.h" +#include "pkcs7_context.h" +#include "signature_info.h" +#include "export_define.h" +#include "openssl/pkcs7.h" +#include "openssl/safestack.h" + +namespace OHOS { +namespace SignatureTools { + +enum SignatureAlgorithm { + ALGORITHM_SHA256_WITH_ECDSA = 0x00000201, + ALGORITHM_SHA384_WITH_ECDSA, + ALGORITHM_SHA512_WITH_ECDSA, + ALGORITHM_SHA256_WITH_DSA = 0x00000301, + ALGORITHM_SHA384_WITH_DSA, + ALGORITHM_SHA512_WITH_DSA, +}; + +class DigestCommon { +public: + DigestCommon() = delete; + + static int32_t GetDigest(const ByteBuffer& chunk, const std::vector& optionalBlocks, + const DigestParameter& digestParameter, unsigned char(&out)[EVP_MAX_MD_SIZE]); + static bool DigestInit(const DigestParameter& digestParameter); + static bool DigestUpdate(const DigestParameter& digestParameter, + const unsigned char content[], int32_t len); + static int32_t GetDigest(const DigestParameter& digestParameter, unsigned char(&out)[EVP_MAX_MD_SIZE]); + static int32_t GetDigestAlgorithmOutputSizeBytes(int32_t nId); + DLL_EXPORT static int32_t GetDigestAlgorithmId(int32_t signAlgorithm); + static std::string GetDigestAlgorithmString(int32_t signAlgorithm); + static void GetOpensslErrorMessage(); + +private: + static bool CheckDigestParameter(const DigestParameter& digestParameter); + + static const int32_t OPENSSL_ERR_MESSAGE_MAX_LEN; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_DIGESTCOMMON_H diff --git a/binary_sign_tool/common/include/digest_parameter.h b/binary_sign_tool/common/include/digest_parameter.h new file mode 100644 index 00000000..082ed8a1 --- /dev/null +++ b/binary_sign_tool/common/include/digest_parameter.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_DIGESTPARAMETER_H +#define SIGNATRUETOOLS_DIGESTPARAMETER_H + +#include "export_define.h" +#include "openssl/ossl_typ.h" + +namespace OHOS { +namespace SignatureTools { + +class DigestParameter { +public: + DLL_EXPORT DigestParameter(); + DLL_EXPORT DigestParameter(const DigestParameter& other); + DLL_EXPORT DigestParameter& operator = (const DigestParameter& other); + DLL_EXPORT ~DigestParameter(); + +public: + int32_t digestOutputSizeBytes; + const EVP_MD* md; + EVP_MD_CTX* ctxPtr; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_DIGESTPARAMETER_H diff --git a/binary_sign_tool/common/include/export_define.h b/binary_sign_tool/common/include/export_define.h new file mode 100644 index 00000000..981967ea --- /dev/null +++ b/binary_sign_tool/common/include/export_define.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_EXPORT_DEFINE_H +#define SIGNATRUETOOLS_EXPORT_DEFINE_H + +#if __GNUC__ >= 4 +#define DLL_EXPORT __attribute__ ((visibility ("default"))) +#define DLL_LOCAL __attribute__ ((visibility ("hidden"))) +#else +#define DLL_EXPORT +#define DLL_LOCAL +#endif + +#endif // SIGNATRUETOOLS_EXPORT_DEFINE_H diff --git a/binary_sign_tool/common/include/localization_adapter.h b/binary_sign_tool/common/include/localization_adapter.h new file mode 100644 index 00000000..980e726a --- /dev/null +++ b/binary_sign_tool/common/include/localization_adapter.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGNATRUETOOLS_LOCALIIZATION_ADAPTER_H +#define SIGNATRUETOOLS_LOCALIIZATION_ADAPTER_H + +#include +#include + +#include "openssl/ssl.h" +#include "openssl/pem.h" +#include "openssl/err.h" +#include "options.h" +#include "key_store_helper.h" +#include "signature_tools_log.h" +#include "digest_common.h" +namespace OHOS { +namespace SignatureTools { +class LocalizationAdapter { +public: + LocalizationAdapter() = default; + LocalizationAdapter(Options* options); + ~LocalizationAdapter() = default; + + int IsAliasExist(const std::string& alias); + int GetKeyPair(bool autoCreate, EVP_PKEY** keyPair); + int IssuerKeyStoreFile(EVP_PKEY** keyPair, bool autoCreate); + int KeyStoreFile(EVP_PKEY** keyPair, bool autoCreate); + + void ResetPwd(); + void SetIssuerKeyStoreFile(bool issuerKeyStoreFile); + void AppAndProfileAssetsRealse(std::initializer_list keys, + std::initializer_list reqs, + std::initializer_list certs); + + bool IsOutFormChain(); + bool IsRemoteSigner(); + + const std::string GetSignAlg() const; + const std::string GetOutFile(); + const std::string GetInFile(); + + Options* GetOptions(); + EVP_PKEY* GetAliasKey(bool autoCreate); + EVP_PKEY* GetIssuerKeyByAlias(); + X509* GetSubCaCertFile(); + X509* GetCaCertFile(); + STACK_OF(X509*) GetSignCertChain(); + std::vector GetCertsFromFile(std::string& certPath, const std::string& logTitle); + +private: + void ResetChars(char* chars); + +public: + Options* options; + std::unique_ptr keyStoreHelper; + +private: + static constexpr int MIN_CERT_CHAIN_SIZE = 2; + static constexpr int MAX_CERT_CHAIN_SIZE = 3; + bool isIssuerKeyStoreFile; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_LOCALIIZATION_ADAPTER_H diff --git a/binary_sign_tool/common/include/options.h b/binary_sign_tool/common/include/options.h new file mode 100644 index 00000000..625fd8f7 --- /dev/null +++ b/binary_sign_tool/common/include/options.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGNATRUETOOLS_OPTIONS_H +#define SIGNATRUETOOLS_OPTIONS_H + +#include +#include +#include +#include + +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { +class Options : public std::unordered_map> { +public: + Options() = default; + ~Options() = default; + char* GetChars(const std::string& key); + std::string GetString(const std::string& key); + std::string GetString(const std::string& key, const std::string& checkStr); + int GetInt(const std::string& key); + bool Equals(const std::string& argf, const std::string& args); + bool Required(const std::initializer_list& keys); + bool IsEmpty(const std::string& cs); + bool GetBool(const std::string& key); + +public: + /* Key alias parameter name. */ + static const std::string KEY_ALIAS; + + /* Key right parameter name. */ + static const std::string KEY_RIGHTS; + + /* Key size parameter name(NIST-P-256, NIST-P-384). */ + static const std::string KEY_SIZE; + + /* Key alg parameter name(ECC). */ + static const std::string KEY_ALG; + + /* Keystore file parameter name. */ + static const std::string KEY_STORE_FILE; + + /* Keystore right parameter name. */ + static const std::string KEY_STORE_RIGHTS; + + /* Issuer key alias parameter name. */ + static const std::string ISSUER_KEY_ALIAS; + + /* Issuer key right parameter name. */ + static const std::string ISSUER_KEY_RIGHTS; + + /* Issuer Key Store File parameter name. */ + static const std::string ISSUER_KEY_STORE_FILE; + + /* Issuer Key Store Pwd parameter name. */ + static const std::string ISSUER_KEY_STORE_RIGHTS; + + /* issuer subject. */ + static const std::string ISSUER; + + /* issuer subject. */ + static const std::string INFORM; + + /* certificate subject. */ + static const std::string SUBJECT; + + /* the validity period of the certificate. */ + static const std::string VALIDITY; + + /* signature algorithm. */ + static const std::string SIGN_ALG; + + /* length of path. */ + static const std::string BASIC_CONSTRAINTS_PATH_LEN; + + /* outfile. */ + static const std::string OUT_FILE; + + /* End file type of cert. values in: cert / certChain */ + static const std::string OUT_FORM; + + /* Sub cert for sig. */ + static const std::string SUB_CA_CERT_FILE; + + /* Ca cert file parameter name. */ + static const std::string CA_CERT_FILE; + + /* In file parameter name. */ + static const std::string IN_FILE; + static const std::string PROFILE_CERT_FILE; + static const std::string APP_CERT_FILE; + static const std::string KEY_USAGE; + static const std::string EXT_KEY_USAGE; + static const std::string KEY_USAGE_CRITICAL; + static const std::string EXT_KEY_USAGE_CRITICAL; + static const std::string BASIC_CONSTRAINTS; + static const std::string BASIC_CONSTRAINTS_CRITICAL; + static const std::string BASIC_CONSTRAINTS_CA; + + /* Out form includes all forms. */ + static const std::string OUT_FORM_SCOPE; + static const std::string MODE; + static const std::string OUT_CERT_CHAIN; + static const std::string OUT_PROFILE; + static const std::string PROOF_FILE; + static const std::string PROFILE_FILE; + static const std::string PROFILE_SIGNED; + static const std::string MODULE_FILE; + static const std::string AD_HOC; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_OPTIONS_H diff --git a/binary_sign_tool/common/include/pkcs7_context.h b/binary_sign_tool/common/include/pkcs7_context.h new file mode 100644 index 00000000..f9e12081 --- /dev/null +++ b/binary_sign_tool/common/include/pkcs7_context.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_PKCS7_CONTEXT_H +#define SIGNATRUETOOLS_PKCS7_CONTEXT_H + +#include +#include +#include "openssl/pkcs7.h" +#include "openssl/x509.h" +#include "byte_buffer.h" +#include "matching_result.h" + +namespace OHOS { +namespace SignatureTools { + +using CertChain = std::vector; +using Pkcs7CertChains = std::vector; + +struct Pkcs7Context { + bool needWriteCrl; + int32_t digestAlgorithm = 0; + MatchingResult matchResult; + std::string certIssuer; + PKCS7* p7; + Pkcs7CertChains certChain; + ByteBuffer content; + Pkcs7Context() + : needWriteCrl(false), digestAlgorithm(0), matchResult(), certIssuer(), + p7(nullptr), certChain(), content() + { + } + ~Pkcs7Context() + { + if (p7 != nullptr) { + PKCS7_free(p7); + p7 = nullptr; + } + for (auto certChain : certChain) { + for (auto cert : certChain) { + X509_free(cert); + } + } + certChain.clear(); + } +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_PKCS7_CONTEXT_H diff --git a/binary_sign_tool/common/include/signature_tools_errno.h b/binary_sign_tool/common/include/signature_tools_errno.h new file mode 100644 index 00000000..cabcc5eb --- /dev/null +++ b/binary_sign_tool/common/include/signature_tools_errno.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATURETOOLS_INDUSTRIAL_BUS_ERRNO_H +#define SIGNATURETOOLS_INDUSTRIAL_BUS_ERRNO_H + +namespace OHOS { +namespace SignatureTools { + +const int RET_OK = 0; +const int RET_FAILED = -1; + +const int COMMAND_ERROR = -101; +/** + * Enum constant FILE_NOT_FOUND. + */ +const int FILE_NOT_FOUND = -102; +/** + * Enum constant IO_ERROR. + */ +const int IO_ERROR = -103; +/** + * Enum constant NOT_SUPPORT_ERROR. + */ +const int NOT_SUPPORT_ERROR = -104; +/** + * Enum constant SIGN_ERROR. + */ +const int SIGN_ERROR = -105; +/** + * Enum constant VERIFY_ERROR. + */ +const int VERIFY_ERROR = -106; +/** + * Enum constant COMMAND_PARAM_ERROR. + */ +const int COMMAND_PARAM_ERROR = -107; +/** + * Enum constant CERTIFICATE_ERROR +*/ +const int CERTIFICATE_ERROR = -108; +/** + * Enum constant KEY_ALIAS_ERROR. + */ +const int KEY_ALIAS_ERROR = -109; +/** + * Enum constant INVALID_ERROR. + */ +const int INVALIDPARAM_ERROR = -110; +/** + * Enum constant ZIP_ERROR. + */ +const int ZIP_ERROR = -111; +/** + * Enum constant FORMAT_ERROR. + */ +const int FORMAT_ERROR = -112; +/** + * Enum constant PARSE_ERROR. + */ +const int PARSE_ERROR = -113; +/** + * Enum constant KEY_PASSWORD_ERROR. + */ +const int KEY_PASSWORD_ERROR = -114; +/** + * Enum constant KEYSTORE_PASSWORD_ERROR. + */ +const int KEYSTORE_PASSWORD_ERROR = -115; +/** + * Enum constant KEYSTORE_STRUCTURE_ERROR. + */ +const int KEYSTORE_STRUCTURE_ERROR = -116; +/** + * Enum constant PROVISION_INVALID_ERROR. + */ +const int PROVISION_INVALID_ERROR = -117; + +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATURETOOLS_INDUSTRIAL_BUS_ERRNO_H \ No newline at end of file diff --git a/binary_sign_tool/common/include/signature_tools_log.h b/binary_sign_tool/common/include/signature_tools_log.h new file mode 100644 index 00000000..03c57c5d --- /dev/null +++ b/binary_sign_tool/common/include/signature_tools_log.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATURETOOLS_SIGNATRUE_TOOLS_LOG_H +#define SIGNATURETOOLS_SIGNATRUE_TOOLS_LOG_H +#include +#include +#include +#include +#include +#include +#include + +#include "signature_tools_errno.h" + +namespace OHOS { +namespace SignatureTools { + +static const char POINT = '.'; +static const char PLACEHOLDER = '0'; +static const int PLACEHOLDERLEN = 3; +static const int SCALE = 1000; + +#define SIGNATURE_LOG(level, fmt, ...) \ + printf("[%s] [%s] [%s] [%d] " fmt "\n", level, __FILE_NAME__, __FUNCTION__, __LINE__, ##__VA_ARGS__) \ + +#ifdef SIGNATURE_LOG_DEBUG +#define SIGNATURE_TOOLS_LOGI(fmt, ...) SIGNATURE_LOG("Info", fmt, ##__VA_ARGS__) +#define SIGNATURE_TOOLS_LOGD(fmt, ...) SIGNATURE_LOG("Debug", fmt, ##__VA_ARGS__) +#define SIGNATURE_TOOLS_LOGW(fmt, ...) SIGNATURE_LOG("Warn", fmt, ##__VA_ARGS__) +#else +#define SIGNATURE_TOOLS_LOGI(fmt, ...) +#define SIGNATURE_TOOLS_LOGD(fmt, ...) +#define SIGNATURE_TOOLS_LOGW(fmt, ...) +#endif + +#define SIGNATURE_TOOLS_LOGF(fmt, ...) SIGNATURE_LOG("Fatal", fmt, ##__VA_ARGS__) +#define SIGNATURE_TOOLS_LOGE(fmt, ...) SIGNATURE_LOG("Error", fmt, ##__VA_ARGS__) + +inline std::string GetSystemTime() +{ + std::string timeBuffer; + std::stringstream ss; + auto now = std::chrono::system_clock::now(); + std::time_t nowTime = std::chrono::system_clock::to_time_t(now); + std::tm* localTime = std::localtime(&nowTime); + auto ms = std::chrono::duration_cast(now.time_since_epoch()) % SCALE; + ss << std::put_time(localTime, "%m-%d %H:%M:%S"); + ss << POINT << std::setfill(PLACEHOLDER) << std::setw(PLACEHOLDERLEN) << ms.count(); + timeBuffer = ss.str(); + return timeBuffer; +} + +/* +* Function: Print the error code and error message to the terminal. +* Parametric Description: command, code, details +* command: Error code variable name as a string. +* code: Error code. +* details: Error description information. +**/ +inline void PrintErrorNumberMsg(const std::string& command, const int code, const std::string& details) +{ + std::cerr << GetSystemTime() << " ERROR - " << command << ", code: " + << code << ". Details: " << details << std::endl; +} + +/* +* Function: Print a prompt to the terminal. +* Parametric Description: message +* message: Prompt Description Information. +**/ +inline void PrintMsg(const std::string& message) +{ + std::cout << GetSystemTime() << " INFO - " << message << std::endl; +} +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATURETOOLS_SIGNATRUE_TOOLS_LOG_H \ No newline at end of file diff --git a/binary_sign_tool/common/signature_tools_common.gni b/binary_sign_tool/common/signature_tools_common.gni new file mode 100644 index 00000000..53c76fd0 --- /dev/null +++ b/binary_sign_tool/common/signature_tools_common.gni @@ -0,0 +1,23 @@ +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("../signature_tools.gni") +signature_tools_common_include = [ "${signature_tools_common}/include" ] + +signature_tools_common_src = [ + "${signature_tools_common}/src/byte_buffer.cpp", + "${signature_tools_common}/src/digest_parameter.cpp", + "${signature_tools_common}/src/digest_common.cpp", + "${signature_tools_common}/src/localization_adapter.cpp", + "${signature_tools_common}/src/options.cpp", +] diff --git a/binary_sign_tool/common/src/byte_buffer.cpp b/binary_sign_tool/common/src/byte_buffer.cpp new file mode 100644 index 00000000..bc6202f7 --- /dev/null +++ b/binary_sign_tool/common/src/byte_buffer.cpp @@ -0,0 +1,642 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "byte_buffer.h" +#include +#include +#include "securec.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { + +const int32_t ByteBuffer::MAX_PRINT_LENGTH = 200; +const int32_t ByteBuffer::HEX_PRINT_LENGTH = 3; +const int64_t MAX_MEMORY = 2L * 1024L * 1024L * 1024L; + +template +std::shared_ptr make_shared_array(size_t size) +{ + if (size == 0) { + return NULL; + } + if (size > MAX_MEMORY) { + SIGNATURE_TOOLS_LOGE("size %zu is too large", size); + return NULL; + } + T* buffer = new (std::nothrow)T[size]; + if (!buffer) { + SIGNATURE_TOOLS_LOGE("new size failed"); + return NULL; + } + return std::shared_ptr(buffer, [] (T* p) { delete[] p; }); +} + +ByteBuffer::ByteBuffer() : buffer(nullptr), position(0), limit(0), capacity(0) +{ +} + +ByteBuffer::ByteBuffer(int32_t bufferCapacity) : buffer(nullptr), position(0), limit(0), capacity(0) +{ + Init(bufferCapacity); +} + +ByteBuffer::ByteBuffer(const char* arr, int32_t length) : buffer(nullptr), position(0), limit(0), capacity(0) +{ + Init(length); + PutData(0, arr, length); +} + +ByteBuffer::ByteBuffer(const ByteBuffer& other) : buffer(nullptr), position(0), limit(0), capacity(0) +{ + Init(other.GetCapacity()); + if (buffer != nullptr && capacity > 0) { + if (memcpy_s(buffer.get(), capacity, other.GetBufferPtr(), other.GetCapacity()) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + return; + } + position = other.GetPosition(); + limit = other.GetLimit(); + } +} + +ByteBuffer::~ByteBuffer() +{ +} + +void ByteBuffer::Init(int32_t bufferCapacity) +{ + if (bufferCapacity > 0) { + buffer = make_shared_array(bufferCapacity); + if (buffer != nullptr) { + if (memset_s(buffer.get(), bufferCapacity, 0, bufferCapacity) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + } + limit = bufferCapacity; + capacity = bufferCapacity; + } + } else { + SIGNATURE_TOOLS_LOGE("bufferCapacity %d is too small", bufferCapacity); + } +} + +ByteBuffer& ByteBuffer::operator=(const ByteBuffer& other) +{ + if (&other == this) { + return *this; + } + // std::unique_ptr reset(),will first release the original object and then point to the new object + buffer = nullptr; + Init(other.GetCapacity()); + if (buffer != nullptr && other.GetBufferPtr() != nullptr && capacity > 0) { + if (memcpy_s(buffer.get(), capacity, other.GetBufferPtr(), other.GetCapacity()) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + return *this; + } + position = other.GetPosition(); + limit = other.GetLimit(); + } + return *this; +} + +bool ByteBuffer::CheckInputForGettingData(int32_t index, int32_t dataLen) +{ + if (buffer == nullptr) { + SIGNATURE_TOOLS_LOGE("buffer is nullptr"); + return false; + } + if (index < 0) { + SIGNATURE_TOOLS_LOGE("invalid index %d", index); + return false; + } + int64_t getDataLast = static_cast(position) + static_cast(index) + + static_cast(dataLen); + if (getDataLast > static_cast(limit)) { + SIGNATURE_TOOLS_LOGE("position: %d, index: %d, limit: %d", position, index, limit); + return false; + } + return true; +} + +bool ByteBuffer::GetInt64(int64_t& value) +{ + if (!GetInt64(0, value)) { + SIGNATURE_TOOLS_LOGE("GetInt64 failed"); + return false; + } + position += sizeof(int64_t); + return true; +} + +bool ByteBuffer::GetInt64(int32_t index, int64_t& value) +{ + if (!CheckInputForGettingData(index, sizeof(int64_t))) { + SIGNATURE_TOOLS_LOGE("Failed to get Int64"); + return false; + } + if (memcpy_s(&value, sizeof(value), (buffer.get() + position + index), sizeof(int64_t)) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + return false; + } + return true; +} + +int32_t ByteBuffer::GetCapacity() const +{ + return capacity; +} + +const char* ByteBuffer::GetBufferPtr() const +{ + return buffer.get(); +} + +bool ByteBuffer::GetInt32(int32_t& value) +{ + if (!GetInt32(0, value)) { + SIGNATURE_TOOLS_LOGE("GetInt32 failed"); + return false; + } + position += sizeof(int32_t); + return true; +} + +bool ByteBuffer::GetInt32(int32_t index, int32_t& value) +{ + if (!CheckInputForGettingData(index, sizeof(int32_t))) { + SIGNATURE_TOOLS_LOGE("Failed to get Int32"); + return false; + } + if (memcpy_s(&value, sizeof(value), (buffer.get() + position + index), sizeof(int32_t)) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + return false; + } + return true; +} + +bool ByteBuffer::GetUInt32(int32_t index, uint32_t& value) +{ + if (!CheckInputForGettingData(index, sizeof(uint32_t))) { + SIGNATURE_TOOLS_LOGE("Failed to get UInt32"); + return false; + } + if (memcpy_s(&value, sizeof(value), (buffer.get() + position + index), sizeof(uint32_t)) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + return false; + } + return true; +} + +bool ByteBuffer::GetUInt32(uint32_t& value) +{ + if (!GetUInt32(0, value)) { + SIGNATURE_TOOLS_LOGE("GetUInt32 failed"); + return false; + } + position += sizeof(uint32_t); + return true; +} + +bool ByteBuffer::GetUInt16(uint16_t& value) +{ + if (!GetUInt16(0, value)) { + SIGNATURE_TOOLS_LOGE("GetUInt16 failed"); + return false; + } + position += sizeof(uint16_t); + return true; +} + +bool ByteBuffer::GetUInt16(int32_t index, uint16_t& value) +{ + if (!CheckInputForGettingData(index, sizeof(uint16_t))) { + SIGNATURE_TOOLS_LOGE("Failed to get UInt16"); + return false; + } + if (memcpy_s(&value, sizeof(value), (buffer.get() + position + index), sizeof(uint16_t)) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + return false; + } + return true; +} + +bool ByteBuffer::GetInt16(int16_t& value) +{ + if (!GetInt16(0, value)) { + SIGNATURE_TOOLS_LOGE("GetInt16 failed"); + return false; + } + position += sizeof(int16_t); + return true; +} + +bool ByteBuffer::GetInt16(int32_t index, int16_t& value) +{ + if (!CheckInputForGettingData(index, sizeof(int16_t))) { + SIGNATURE_TOOLS_LOGE("Failed to get Int16"); + return false; + } + if (memcpy_s(&value, sizeof(value), (buffer.get() + position + index), sizeof(int16_t)) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + return false; + } + return true; +} + +bool ByteBuffer::GetUInt8(uint8_t& value) +{ + if (!GetUInt8(0, value)) { + SIGNATURE_TOOLS_LOGE("GetUInt8 failed"); + return false; + } + position += sizeof(uint8_t); + return true; +} + +bool ByteBuffer::GetUInt8(int32_t index, uint8_t& value) +{ + if (!CheckInputForGettingData(index, sizeof(uint8_t))) { + SIGNATURE_TOOLS_LOGE("Failed to get UInt8"); + return false; + } + if (memcpy_s(&value, sizeof(value), (buffer.get() + position + index), sizeof(uint8_t)) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + return false; + } + return true; +} + +bool ByteBuffer::GetInt8(int8_t& value) +{ + if (!GetInt8(0, value)) { + SIGNATURE_TOOLS_LOGE("GetInt8 failed"); + return false; + } + position += sizeof(int8_t); + return true; +} + +bool ByteBuffer::GetInt8(int32_t index, int8_t& value) +{ + if (!CheckInputForGettingData(index, sizeof(int8_t))) { + SIGNATURE_TOOLS_LOGE("Failed to get Int8"); + return false; + } + if (memcpy_s(&value, sizeof(value), (buffer.get() + position + index), sizeof(int8_t)) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + return false; + } + return true; +} + +void ByteBuffer::PutInt64(int64_t value) +{ + if ((limit - position) >= static_cast(sizeof(value))) { + if (memcpy_s(buffer.get() + position, limit - position, &value, sizeof(value)) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + } else { + position += sizeof(value); + } + } +} + +void ByteBuffer::PutInt32(int32_t offset, int32_t value) +{ + if (buffer != nullptr && offset >= 0 && limit - offset >= static_cast(sizeof(value))) { + if (memcpy_s((buffer.get() + offset), (limit - offset), &value, sizeof(value)) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + } + } +} + +void ByteBuffer::PutInt16(int32_t offset, int16_t value) +{ + if (buffer != nullptr && offset >= 0 && limit - offset >= static_cast(sizeof(value))) { + if (memcpy_s((buffer.get() + offset), (limit - offset), &value, sizeof(value)) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + } + } +} + +void ByteBuffer::PutByte(int32_t offset, char value) +{ + if (buffer != nullptr && offset >= 0 && limit - offset >= static_cast(sizeof(value))) { + if (memcpy_s((buffer.get() + offset), (limit - offset), (&value), sizeof(value)) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + } + } +} + +void ByteBuffer::PutData(int32_t offset, const char data[], int32_t len) +{ + if (buffer != nullptr && data != nullptr && offset >= 0 && len > 0 && (limit - offset) >= len) { + if (memcpy_s((buffer.get() + offset), (limit - offset), data, len) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + } + } +} + +void ByteBuffer::PutData(int32_t offset, const int8_t data[], int32_t len) +{ + if (buffer != nullptr && data != nullptr && offset >= 0 && len > 0 && (limit - offset) >= len) { + if (memcpy_s((buffer.get() + offset), (limit - offset), data, len) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + } + } +} + +void ByteBuffer::PutData(int32_t offset, const char data[], int32_t len, int32_t type) +{ + static int offsetAdd = 0; + if (buffer != nullptr && data != nullptr && offset >= 0 && len > 0 && (limit - offset) >= len) { + if (memcpy_s((buffer.get() + offsetAdd), (limit - offsetAdd), data, len) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + } + offsetAdd += offset; + } +} + +void ByteBuffer::PutInt32(int32_t value) +{ + if (limit - position >= static_cast(sizeof(value))) { + if (memcpy_s(buffer.get() + position, limit - position, &value, sizeof(value)) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + } else { + position += sizeof(value); + } + } +} + +void ByteBuffer::PutInt16(int16_t value) +{ + if (limit - position >= static_cast(sizeof(value))) { + if (memcpy_s(buffer.get() + position, limit - position, &value, sizeof(value)) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + } else { + position += sizeof(value); + } + } +} + +void ByteBuffer::PutUInt8(uint8_t value) +{ + if (limit - position >= static_cast(sizeof(value))) { + if (memcpy_s(buffer.get() + position, limit - position, &value, sizeof(value)) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + } else { + position += sizeof(value); + } + } +} + +void ByteBuffer::PutUInt16(uint16_t value) +{ + if (limit - position >= static_cast(sizeof(value))) { + if (memcpy_s(buffer.get() + position, limit - position, &value, sizeof(value)) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + } else { + position += sizeof(value); + } + } +} + +void ByteBuffer::PutUInt32(uint32_t value) +{ + if (limit - position >= static_cast(sizeof(value))) { + if (memcpy_s(buffer.get() + position, limit - position, &value, sizeof(value)) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + } else { + position += sizeof(value); + } + } +} + +void ByteBuffer::ClearData() +{ + if (buffer != nullptr && position < capacity) { + if (memset_s(buffer.get() + position, capacity - position, 0, capacity - position) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + } + } +} + +void ByteBuffer::PutByte(char value) +{ + if (buffer != nullptr && limit - position >= static_cast(sizeof(value))) { + if (memcpy_s(buffer.get() + position, limit - position, &value, sizeof(value)) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + } else { + position += sizeof(value); + } + } +} + +void ByteBuffer::Put(const ByteBuffer& byteBuffer) +{ + PutData(byteBuffer.GetBufferPtr(), byteBuffer.Remaining()); +} + +void ByteBuffer::PutData(const char data[], int32_t len) +{ + if (buffer != nullptr && data != nullptr && len > 0 && (limit - position) >= len) { + if (memcpy_s((buffer.get() + position), (limit - position), data, len) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + } else { + position += len; + } + } +} + +void ByteBuffer::PutData(int8_t data[], int32_t len) +{ + if (buffer != nullptr && data != nullptr && len > 0 && (limit - position) >= len) { + if (memcpy_s((buffer.get() + position), (limit - position), data, len) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + } else { + position += len; + } + } +} + +void ByteBuffer::GetByte(int8_t data[], int32_t len) +{ + if (0 == memcpy_s(data, len, buffer.get() + position, len)) { + position = position + len; + } +} + +void ByteBuffer::GetData(char data[], uint32_t len) +{ + if (0 == memcpy_s(data, len, buffer.get() + position, len)) { + position = position + len; + } +} + +void ByteBuffer::GetData(int32_t offset, int8_t data[], uint32_t len) +{ + if (0 == memcpy_s(data, len, buffer.get() + offset, len)) { + position = position + len; + } +} + +void ByteBuffer::SetPosition(int32_t pos) +{ + if (pos >= 0 && pos <= limit) { + position = pos; + } +} + +ByteBuffer& ByteBuffer::slice_for_codesigning() +{ + if (position >= capacity || limit > capacity || position >= limit || buffer == nullptr) { + SIGNATURE_TOOLS_LOGE("position %d capacity %d limit %d error", position, capacity, limit); + return *this; + } + int32_t rem = (position <= limit ? limit - position : 0); + + position = 0; + capacity = rem; + limit = rem; + return *this; +} + +ByteBuffer& ByteBuffer::Slice() +{ + if (position >= capacity || limit > capacity || position >= limit || buffer == nullptr) { + SIGNATURE_TOOLS_LOGE("position %d capacity %d limit %d error", + position, capacity, limit); + return *this; + } + int32_t newCapacity = limit - position; + auto newBuffer = make_shared_array(newCapacity); + if (newBuffer == nullptr) { + SIGNATURE_TOOLS_LOGE("make_shared_array failed"); + return *this; + } + if (memcpy_s(newBuffer.get(), newCapacity, buffer.get() + position, newCapacity) != RET_OK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + return *this; + } + buffer = std::move(newBuffer); + position = 0; + capacity = newCapacity; + limit = capacity; + + return *this; +} + +ByteBuffer* ByteBuffer::Duplicate() +{ + ByteBuffer* newBuffer = new ByteBuffer(); + newBuffer->buffer = buffer; + newBuffer->limit = limit; + newBuffer->capacity = capacity; + newBuffer->position = position; + return newBuffer; +} + +int32_t ByteBuffer::GetPosition() const +{ + return position; +} + +int32_t ByteBuffer::GetLimit() const +{ + return limit; +} + +void ByteBuffer::SetLimit(int32_t lim) +{ + if (lim <= capacity && lim >= position) { + limit = lim; + } +} + +int32_t ByteBuffer::Remaining() const +{ + return position < limit ? limit - position : 0; +} + +bool ByteBuffer::HasRemaining() const +{ + return position < limit; +} + +void ByteBuffer::Clear() +{ + position = 0; + limit = capacity; +} + +ByteBuffer& ByteBuffer::Flip() +{ + limit = position; + position = 0; + return *this; +} + +bool ByteBuffer::IsEqual(const ByteBuffer& other) +{ + if (&other == this) { + return true; + } + if (capacity != other.GetCapacity() || other.GetBufferPtr() == nullptr || buffer == nullptr) { + SIGNATURE_TOOLS_LOGE("invalid input"); + return false; + } + const char* otherBuffer = other.GetBufferPtr(); + for (int32_t i = 0; i < capacity; i++) { + if (buffer.get()[i] != otherBuffer[i]) { + SIGNATURE_TOOLS_LOGE("diff value[%d]: %x %x", + i, buffer.get()[i], otherBuffer[i]); + return false; + } + } + return true; +} + +bool ByteBuffer::IsEqual(const std::string& other) +{ + if (capacity != static_cast(other.size()) || buffer == nullptr) { + SIGNATURE_TOOLS_LOGE("invalid input"); + return false; + } + for (int32_t i = 0; i < capacity; i++) { + if (buffer.get()[i] != other[i]) { + SIGNATURE_TOOLS_LOGE("diff value[%d]: %x %x", + i, buffer.get()[i], other[i]); + return false; + } + } + return true; +} + +void ByteBuffer::SetCapacity(int32_t cap) +{ + if (buffer != nullptr) { + buffer = nullptr; + position = 0; + limit = 0; + capacity = 0; + } + Init(cap); +} + +std::string ByteBuffer::ToString() +{ + return std::string(GetBufferPtr(), GetCapacity()); +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/common/src/digest_common.cpp b/binary_sign_tool/common/src/digest_common.cpp new file mode 100644 index 00000000..36a694b9 --- /dev/null +++ b/binary_sign_tool/common/src/digest_common.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "digest_common.h" +#include "signature_tools_log.h" +#include "openssl/err.h" + +namespace OHOS { +namespace SignatureTools { +const int32_t DigestCommon::OPENSSL_ERR_MESSAGE_MAX_LEN = 1024; + +int32_t DigestCommon::GetDigestAlgorithmOutputSizeBytes(int32_t nId) +{ + return EVP_MD_size(EVP_get_digestbynid(nId)); +} + +bool DigestCommon::CheckDigestParameter(const DigestParameter& digestParameter) +{ + if (digestParameter.md == nullptr) { + SIGNATURE_TOOLS_LOGE("md is nullptr"); + return false; + } + if (digestParameter.ctxPtr == nullptr) { + SIGNATURE_TOOLS_LOGE("ctxPtr is nullptr"); + return false; + } + return true; +} + +bool DigestCommon::DigestInit(const DigestParameter& digestParameter) +{ + if (!CheckDigestParameter(digestParameter)) { + return false; + } + if (EVP_DigestInit(digestParameter.ctxPtr, digestParameter.md) <= 0) { + GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("EVP_DigestInit failed"); + return false; + } + return true; +} + +/* the caller must ensure that EVP_DigestInit was called before calling this function */ +bool DigestCommon::DigestUpdate(const DigestParameter& digestParameter, + const unsigned char content[], int32_t len) +{ + if (content == nullptr) { + SIGNATURE_TOOLS_LOGE("content is nullptr"); + return false; + } + if (!CheckDigestParameter(digestParameter)) { + return false; + } + if (EVP_DigestUpdate(digestParameter.ctxPtr, content, len) <= 0) { + GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("EVP_DigestUpdate failed"); + return false; + } + return true; +} + +int32_t DigestCommon::GetDigest(const DigestParameter& digestParameter, + unsigned char(&out)[EVP_MAX_MD_SIZE]) +{ + uint32_t outLen = 0; + if (!CheckDigestParameter(digestParameter)) { + return outLen; + } + if (EVP_DigestFinal(digestParameter.ctxPtr, out, &outLen) <= 0) { + GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("EVP_DigestFinal failed"); + outLen = 0; + } + return outLen; +} + +int32_t DigestCommon::GetDigest(const ByteBuffer& chunk, + const std::vector& optionalBlocks, + const DigestParameter& digestParameter, + unsigned char(&out)[EVP_MAX_MD_SIZE]) +{ + int32_t chunkLen = chunk.Remaining(); + uint32_t outLen = 0; + if (digestParameter.md == nullptr) { + SIGNATURE_TOOLS_LOGE("md is nullprt"); + return outLen; + } + if (digestParameter.ctxPtr == nullptr) { + SIGNATURE_TOOLS_LOGE("ctxPtr is nullprt"); + return outLen; + } + if (EVP_DigestInit(digestParameter.ctxPtr, digestParameter.md) <= 0) { + GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("EVP_DigestInit failed"); + return outLen; + } + if (EVP_DigestUpdate(digestParameter.ctxPtr, chunk.GetBufferPtr(), chunkLen) <= 0) { + GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("EVP_DigestUpdate chunk failed"); + return outLen; + } + for (int32_t i = 0; i < static_cast(optionalBlocks.size()); i++) { + chunkLen = optionalBlocks[i].optionalBlockValue.GetCapacity(); + if (EVP_DigestUpdate(digestParameter.ctxPtr, optionalBlocks[i].optionalBlockValue.GetBufferPtr(), + chunkLen) <= 0) { + GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("EVP_DigestUpdate %dst optional block failed", i); + return outLen; + } + } + if (EVP_DigestFinal(digestParameter.ctxPtr, out, &outLen) <= 0) { + GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("EVP_DigestFinal failed"); + outLen = 0; + } + return outLen; +} + +void DigestCommon::GetOpensslErrorMessage() +{ + unsigned long retOpenssl; + char errOpenssl[OPENSSL_ERR_MESSAGE_MAX_LEN]; + while ((retOpenssl = ERR_get_error()) != 0) { + ERR_error_string(retOpenssl, errOpenssl); + SIGNATURE_TOOLS_LOGE("openssl err: %lu, message: %s", retOpenssl, errOpenssl); + } +} + +int32_t DigestCommon::GetDigestAlgorithmId(int32_t signAlgorithm) +{ + switch (signAlgorithm) { + case ALGORITHM_SHA256_WITH_ECDSA: + case ALGORITHM_SHA256_WITH_DSA: + return NID_sha256; + case ALGORITHM_SHA384_WITH_ECDSA: + case ALGORITHM_SHA384_WITH_DSA: + return NID_sha384; + case ALGORITHM_SHA512_WITH_ECDSA: + case ALGORITHM_SHA512_WITH_DSA: + return NID_sha512; + default: + SIGNATURE_TOOLS_LOGE("signAlgorithm: %d error", signAlgorithm); + return NID_undef; + } +} + +std::string DigestCommon::GetDigestAlgorithmString(int32_t signAlgorithm) +{ + switch (signAlgorithm) { + case ALGORITHM_SHA256_WITH_ECDSA: + return "SHA-256"; + case ALGORITHM_SHA384_WITH_ECDSA: + return "SHA-384"; + case ALGORITHM_SHA512_WITH_ECDSA: + return "SHA-512"; + default: + SIGNATURE_TOOLS_LOGE("signAlgorithm: %d error", signAlgorithm); + return ""; + } +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/common/src/digest_parameter.cpp b/binary_sign_tool/common/src/digest_parameter.cpp new file mode 100644 index 00000000..3ec07c05 --- /dev/null +++ b/binary_sign_tool/common/src/digest_parameter.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "digest_parameter.h" +#include "openssl/evp.h" + +namespace OHOS { +namespace SignatureTools { +DigestParameter::DigestParameter() : digestOutputSizeBytes(0), md(nullptr), ctxPtr(nullptr) +{ +} + +DigestParameter::~DigestParameter() +{ + if (ctxPtr != nullptr) { + EVP_MD_CTX_destroy(ctxPtr); + ctxPtr = nullptr; + } + /* md points to the OpenSSL global static struct constant, no need to free. */ + md = nullptr; +} + +DigestParameter::DigestParameter(const DigestParameter& other) +{ + digestOutputSizeBytes = other.digestOutputSizeBytes; + md = other.md; + ctxPtr = EVP_MD_CTX_create(); + EVP_MD_CTX_copy(ctxPtr, other.ctxPtr); +} + +DigestParameter& DigestParameter::operator = (const DigestParameter& other) +{ + if (ctxPtr != nullptr) { + EVP_MD_CTX_destroy(ctxPtr); + ctxPtr = nullptr; + } + digestOutputSizeBytes = other.digestOutputSizeBytes; + md = other.md; + ctxPtr = EVP_MD_CTX_create(); + EVP_MD_CTX_copy(ctxPtr, other.ctxPtr); + return *this; +} +} +} \ No newline at end of file diff --git a/binary_sign_tool/common/src/localization_adapter.cpp b/binary_sign_tool/common/src/localization_adapter.cpp new file mode 100644 index 00000000..edb38cdc --- /dev/null +++ b/binary_sign_tool/common/src/localization_adapter.cpp @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +#include "localization_adapter.h" +#include "constant.h" +#include +#include +#include +#include +#include + +namespace OHOS { +namespace SignatureTools { + +LocalizationAdapter::LocalizationAdapter(Options* options) +{ + this->options = options; + this->keyStoreHelper = std::make_unique(); + this->isIssuerKeyStoreFile = false; +} + +int LocalizationAdapter::IsAliasExist(const std::string& alias) +{ + std::string keyStoreFile = options->GetString(Options::KEY_STORE_FILE); + if (!keyStoreHelper->IsKeyStoreFileExist(keyStoreFile)) { + return RET_FAILED; + } + + EVP_PKEY* keyPair = nullptr; + char* keyStorePwd = options->GetChars(Options::KEY_STORE_RIGHTS); + char* keyPwd = options->GetChars(Options::KEY_RIGHTS); + keyStoreHelper->SetIsRegen(true); + int status = keyStoreHelper->ReadKeyStore(keyStoreFile, keyStorePwd, alias, keyPwd, &keyPair); + EVP_PKEY_free(keyPair); + if (status == RET_OK) { + return RET_OK; + } + + return RET_FAILED; +} + +void LocalizationAdapter::ResetPwd() +{ + char* keyRights = options->GetChars(Options::KEY_RIGHTS); + if (keyRights != nullptr) { + ResetChars(keyRights); + } + char* keyStoreRights = options->GetChars(Options::KEY_STORE_RIGHTS); + if (keyStoreRights != nullptr) { + ResetChars(keyStoreRights); + } + char* issuerKeyRights = options->GetChars(Options::ISSUER_KEY_RIGHTS); + if (issuerKeyRights != nullptr) { + ResetChars(issuerKeyRights); + } + char* issuerKeyStoreRights = options->GetChars(Options::ISSUER_KEY_STORE_RIGHTS); + if (issuerKeyStoreRights != nullptr) { + ResetChars(issuerKeyStoreRights); + } +} + +void LocalizationAdapter::ResetChars(char* chars) +{ + if (chars == NULL) { + return; + } + for (size_t i = 0; i < strlen(chars); i++) { + chars[i] = 0; + } +} + +EVP_PKEY* LocalizationAdapter::GetAliasKey(bool autoCreate) +{ + EVP_PKEY* keyPair = nullptr; + if (keyStoreHelper == nullptr) { + keyStoreHelper = std::make_unique(); + } + + int status = GetKeyPair(autoCreate, &keyPair); + if (status == RET_FAILED) { + EVP_PKEY_free(keyPair); + return nullptr; + } + + return keyPair; +} + +int LocalizationAdapter::GetKeyPair(bool autoCreate, EVP_PKEY** keyPair) +{ + keyStoreHelper->SetPassWordStatus(true); + keyStoreHelper->SetIsRegen(autoCreate); + + int status = RET_FAILED; + if (isIssuerKeyStoreFile) { + status = IssuerKeyStoreFile(keyPair, autoCreate); + } else { + status = KeyStoreFile(keyPair, autoCreate); + } + isIssuerKeyStoreFile = false; + return status; +} + +int LocalizationAdapter::KeyStoreFile(EVP_PKEY** keyPair, bool autoCreate) +{ + std::string keyStorePath = ""; + keyStorePath = options->GetString(Options::KEY_STORE_FILE); + char* keyStorePwd = options->GetChars(Options::KEY_STORE_RIGHTS); + char* keyPwd = options->GetChars(Options::KEY_RIGHTS); + std::string keyAlias = options->GetString(Options::KEY_ALIAS); + bool fileStatus = keyStoreHelper->IsKeyStoreFileExist(keyStorePath); + if (fileStatus) { + int status = keyStoreHelper->ReadKeyStore(keyStorePath, keyStorePwd, keyAlias, keyPwd, keyPair); + if (status == RET_OK) { + return RET_OK; + } + + if (!keyStoreHelper->GetPassWordStatus()) { + autoCreate = false; + } + } + if (autoCreate) { + std::string keyAlg = options->GetString(Options::KEY_ALG); + int keySize = options->GetInt(Options::KEY_SIZE); + *keyPair = keyStoreHelper->GenerateKeyPair(keyAlg, keySize); + int status = keyStoreHelper->WriteKeyStore(*keyPair, keyStorePath, keyStorePwd, keyAlias, keyPwd); + if (status == RET_OK) { + PrintMsg("Remind: generate new keypair ,the keyalias is " + keyAlias + " !"); + return RET_OK; + } + } + + return RET_FAILED; +} + +int LocalizationAdapter::IssuerKeyStoreFile(EVP_PKEY** keyPair, bool autoCreate) +{ + std::string keyStore = options->GetString(Options::ISSUER_KEY_STORE_FILE); + char* keyStorePwd = options->GetChars(Options::ISSUER_KEY_STORE_RIGHTS); + std::string keyAlias = options->GetString(Options::ISSUER_KEY_ALIAS); + char* keyPwd = options->GetChars(Options::ISSUER_KEY_RIGHTS); + + if (keyStore.empty()) { + keyStore = options->GetString(Options::KEY_STORE_FILE); + keyStorePwd = options->GetChars(Options::KEY_STORE_RIGHTS); + } + + bool fileStatus = keyStoreHelper->IsKeyStoreFileExist(keyStore); + if (fileStatus) { + int status = keyStoreHelper->ReadKeyStore(keyStore, keyStorePwd, keyAlias, keyPwd, keyPair); + if (status == RET_OK) { + return RET_OK; + } + + if (!keyStoreHelper->GetPassWordStatus()) { + autoCreate = false; + } + } + + if (!fileStatus && !keyStore.empty() && !autoCreate) { + PrintErrorNumberMsg("KEY_ALIAS_ERROR", KEY_ALIAS_ERROR, "keyAlias: '" + + keyAlias + "' is not exist in" + keyStore); + } + + if (autoCreate) { + std::string keyAlg = options->GetString(Options::KEY_ALG); + int keySize = options->GetInt(Options::KEY_SIZE); + *keyPair = keyStoreHelper->GenerateKeyPair(keyAlg, keySize); + if (keyStore.empty()) { + return keyStoreHelper->WriteKeyStore(*keyPair, keyStore, keyStorePwd, keyAlias, keyPwd); + } + } + + return RET_FAILED; +} + +void LocalizationAdapter::SetIssuerKeyStoreFile(bool issuerKeyStoreFile) +{ + this->isIssuerKeyStoreFile = issuerKeyStoreFile; +} + +STACK_OF(X509)* LocalizationAdapter::GetSignCertChain() +{ + STACK_OF(X509)* certificates = NULL; + std::string certPath = options->GetString(Options::PROFILE_CERT_FILE); + if (certPath.empty()) { + certPath = options->GetString(Options::APP_CERT_FILE); + } + certificates = sk_X509_new(NULL); + if (certificates == NULL) { + SIGNATURE_TOOLS_LOGE("sk_X509_new failed"); + return NULL; + } + std::vector certs = GetCertsFromFile(certPath, Options::PROFILE_CERT_FILE); + for (int i = 0; i < static_cast(certs.size()); i++) { + sk_X509_push(certificates, certs[i]); + } + if (sk_X509_num(certificates) < MIN_CERT_CHAIN_SIZE || sk_X509_num(certificates) > MAX_CERT_CHAIN_SIZE) { + SIGNATURE_TOOLS_LOGE("Profile cert '%s' must a cert chain", certPath.c_str()); + goto err; + } + return certificates; +err: + sk_X509_pop_free(certificates, X509_free); + return NULL; +} + +EVP_PKEY* LocalizationAdapter::GetIssuerKeyByAlias() +{ + return GetAliasKey(false); +} + +bool LocalizationAdapter::IsOutFormChain() +{ + std::string checkStr = OUT_FORM_CERT_CHAIN; + std::string outForm = options->GetString(Options::OUT_FORM, checkStr); + if (outForm.compare(OUT_FORM_CERT_CHAIN) == 0) { + return true; + } + return false; +} + +X509* LocalizationAdapter::GetSubCaCertFile() +{ + std::string certPath = options->GetString(Options::SUB_CA_CERT_FILE); + return GetCertsFromFile(certPath, Options::SUB_CA_CERT_FILE).at(0); +} + +const std::string LocalizationAdapter::GetSignAlg() const +{ + return options->GetString(Options::SIGN_ALG); +} + +X509* LocalizationAdapter::GetCaCertFile() +{ + std::string certPath = options->GetString(Options::CA_CERT_FILE); + return GetCertsFromFile(certPath, Options::CA_CERT_FILE).at(0); +} + +const std::string LocalizationAdapter::GetOutFile() +{ + return options->GetString(Options::OUT_FILE); +} + +std::vector LocalizationAdapter::GetCertsFromFile(std::string& certPath, const std::string& logTitle) +{ + SIGNATURE_TOOLS_LOGD("outPutPath = %s , logTitle = %s", certPath.c_str(), logTitle.c_str()); + std::vector certs; + if (certPath.empty()) { + SIGNATURE_TOOLS_LOGE("cert path not exist!"); + return certs; + } + // Read And Get Cert + BIO* bio = BIO_new_file(certPath.c_str(), "rb"); + if (!bio) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open file:" + certPath + "failed"); + DigestCommon::GetOpensslErrorMessage(); + BIO_free(bio); + return certs; + } + X509* cert = nullptr; + while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != nullptr) { + certs.emplace_back(cert); + } + BIO_free(bio); + return certs; +} + +const std::string LocalizationAdapter::GetInFile() +{ + return options->GetString(Options::IN_FILE); +} + +bool LocalizationAdapter::IsRemoteSigner() +{ + std::string mode = options->GetString(Options::MODE, LOCAL_SIGN); + return mode == REMOTE_SIGN; +} + +Options* LocalizationAdapter::GetOptions() +{ + return options; +} + +void LocalizationAdapter::AppAndProfileAssetsRealse(std::initializer_list keys, + std::initializer_list reqs, + std::initializer_list certs) +{ + for (auto cert : certs) { + if (cert) { + X509_free(cert); + cert = nullptr; + } + } + for (auto req : reqs) { + if (req) { + X509_REQ_free(req); + req = nullptr; + } + } + for (auto key : keys) { + if (key) { + EVP_PKEY_free(key); + key = nullptr; + } + } +} + +} // namespace SignatureTools +} // namespace OHOS + diff --git a/binary_sign_tool/common/src/options.cpp b/binary_sign_tool/common/src/options.cpp new file mode 100644 index 00000000..a3f7d7dd --- /dev/null +++ b/binary_sign_tool/common/src/options.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "options.h" + +namespace OHOS { +namespace SignatureTools { + +/* Initializes the static member constant. */ +const std::string Options::KEY_ALIAS = "keyAlias"; +const std::string Options::KEY_RIGHTS = "keyPwd"; +const std::string Options::KEY_ALG = "keyAlg"; +const std::string Options::KEY_SIZE = "keySize"; +const std::string Options::KEY_STORE_FILE = "keystoreFile"; +const std::string Options::KEY_STORE_RIGHTS = "keystorePwd"; +const std::string Options::ISSUER_KEY_ALIAS = "issuerKeyAlias"; +const std::string Options::ISSUER_KEY_RIGHTS = "issuerKeyPwd"; +const std::string Options::ISSUER_KEY_STORE_FILE = "issuerKeystoreFile"; +const std::string Options::ISSUER_KEY_STORE_RIGHTS = "issuerKeystorePwd"; +const std::string Options::ISSUER = "issuer"; +const std::string Options::SUBJECT = "subject"; +const std::string Options::VALIDITY = "validity"; +const std::string Options::SIGN_ALG = "signAlg"; +const std::string Options::BASIC_CONSTRAINTS_PATH_LEN = "basicConstraintsPathLen"; +const std::string Options::OUT_FILE = "outFile"; +const std::string Options::OUT_FORM = "outForm"; +const std::string Options::SUB_CA_CERT_FILE = "subCaCertFile"; +const std::string Options::CA_CERT_FILE = "rootCaCertFile"; +const std::string Options::IN_FILE = "inFile"; +const std::string Options::PROFILE_CERT_FILE = "profileCertFile"; +const std::string Options::APP_CERT_FILE = "appCertFile"; +const std::string Options::KEY_USAGE = "keyUsage"; +const std::string Options::EXT_KEY_USAGE = "extKeyUsage"; +const std::string Options::KEY_USAGE_CRITICAL = "keyUsageCritical"; +const std::string Options::EXT_KEY_USAGE_CRITICAL = "extKeyUsageCritical"; +const std::string Options::BASIC_CONSTRAINTS_CA = "basicConstraintsCa"; +const std::string Options::BASIC_CONSTRAINTS_CRITICAL = "basicConstraintsCritical"; +const std::string Options::BASIC_CONSTRAINTS = "basicConstraints"; +const std::string Options::OUT_FORM_SCOPE = "cert,certChain"; +const std::string Options::MODE = "mode"; +const std::string Options::INFORM = "inForm"; +const std::string Options::OUT_CERT_CHAIN = "outCertChain"; +const std::string Options::OUT_PROFILE = "outProfile"; +const std::string Options::PROOF_FILE = "outproof"; +const std::string Options::PROFILE_FILE = "profileFile"; +const std::string Options::PROFILE_SIGNED = "profileSigned"; +const std::string Options::MODULE_FILE = "moduleFile"; +const std::string Options::AD_HOC = "adHoc"; + +char* Options::GetChars(const std::string& key) +{ + if (this->count(key) == 0) { + return nullptr; + } + + auto value = (*this)[key]; + char** charsPtr = std::get_if(&value); + if (charsPtr == nullptr) { + SIGNATURE_TOOLS_LOGI("GetChars key = %s value = nullptr !", key.c_str()); + return nullptr; + } + return *charsPtr; +} + +std::string Options::GetString(const std::string& key) +{ + if (this->count(key) == 0) { + return ""; + } + + auto value = (*this)[key]; + std::string* stringPtr = std::get_if(&value); + if (stringPtr == nullptr) { + SIGNATURE_TOOLS_LOGI("GetString key = %s value = """, key.c_str()); + return ""; + } + return *stringPtr; +} + +std::string Options::GetString(const std::string& key, const std::string& checkStr) +{ + if (this->count(key) == 0) { + return ""; + } + + auto value = (*this)[key]; + std::string* stringPtr = std::get_if(&value); + if (stringPtr == nullptr || *stringPtr == "") { + SIGNATURE_TOOLS_LOGI("GetString key = %s value = %s ", key.c_str(), checkStr.c_str()); + return checkStr; + } + return *stringPtr; +} + +int Options::GetInt(const std::string& key) +{ + if (this->count(key) == 0) { + return 0; + } + + auto value = (*this)[key]; + int* stringPtr = std::get_if(&value); + if (stringPtr == nullptr) { + SIGNATURE_TOOLS_LOGI("GetInt key = %s value = 0 ", key.c_str()); + return 0; + } + return *stringPtr; +} + +bool Options::Equals(const std::string& argf, const std::string& args) +{ + std::string ksFile = GetString(argf); + std::string iksFile = GetString(args); + if (ksFile == iksFile) { + return true; + } + return false; +} + +bool Options::Required(const std::initializer_list& keys) +{ + for (auto& key : keys) { + if (!this->IsEmpty(key) && !(this->find(key) != this->end())) { + PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "Params '-" + key + "' is required"); + return false; + } + } + return true; +} + +bool Options::IsEmpty(const std::string& cs) +{ + if (cs.empty()) { + return true; + } + return false; +} + +bool Options::GetBool(const std::string& key) +{ + auto value = (*this)[key]; + bool* stringPtr = std::get_if(&value); + return *stringPtr; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/hap/config/include/signer_config.h b/binary_sign_tool/hap/config/include/signer_config.h new file mode 100644 index 00000000..df939ae5 --- /dev/null +++ b/binary_sign_tool/hap/config/include/signer_config.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_SIGNER_CONFIG_H +#define SIGNATRUETOOLS_SIGNER_CONFIG_H +#include +#include +#include +#include + +#include "options.h" +#include "openssl/x509.h" +#include "signature_algorithm_helper.h" +#include "signer.h" + +namespace OHOS { +namespace SignatureTools { +class SignerConfig { +public: + SignerConfig(); + ~SignerConfig(); + Options* GetOptions() const; + void SetOptions(Options* optionsParam); + STACK_OF(X509)* GetCertificates() const; + void SetCertificates(STACK_OF(X509)* certificatesParam); + STACK_OF(X509_CRL)* GetX509CRLs() const; + void SetX509CRLs(STACK_OF(X509_CRL)* crls); + std::vector GetSignatureAlgorithms() const; + void SetSignatureAlgorithms(const std::vector& signatureAlgorithmsParam); + const std::map& GetSignParamMap() const; + void FillParameters(const std::map& params); + std::shared_ptr GetSigner(); + int GetCompatibleVersion() const; + void SetCompatibleVersion(int compatibleVersionParam); + +private: + bool IsInputCertChainNotEmpty() const; + bool IsInputCrlNotEmpty() const; + Options* options; + STACK_OF(X509)* certificates; + STACK_OF(X509_CRL)* x509CRLs; + std::vector signatureAlgorithms; + std::map signParamMap; + std::shared_ptr signer; + int compatibleVersion; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_SIGNER_CONFIG_H diff --git a/binary_sign_tool/hap/config/src/signer_config.cpp b/binary_sign_tool/hap/config/src/signer_config.cpp new file mode 100644 index 00000000..382e94b2 --- /dev/null +++ b/binary_sign_tool/hap/config/src/signer_config.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include + +#include "signer_factory.h" +#include "localization_adapter.h" +#include "signer_config.h" + +namespace OHOS { +namespace SignatureTools { +SignerConfig::SignerConfig() : options(nullptr), + certificates(nullptr), + x509CRLs(nullptr), + signer(nullptr), + compatibleVersion(0) +{ +} + +SignerConfig::~SignerConfig() +{ + if (certificates) { + sk_X509_pop_free(certificates, X509_free); + } + certificates = NULL; + + if (x509CRLs) { + sk_X509_CRL_pop_free(x509CRLs, X509_CRL_free); + } + x509CRLs = NULL; +} + +Options* SignerConfig::GetOptions() const +{ + return options; +} + +void SignerConfig::SetOptions(Options* optionsParam) +{ + options = optionsParam; +} + +STACK_OF(X509)* SignerConfig::GetCertificates() const +{ + if (IsInputCertChainNotEmpty() || signer == nullptr) { + return certificates; + } + return signer->GetCertificates(); +} + +void SignerConfig::SetCertificates(STACK_OF(X509)* certificatesParam) +{ + certificates = certificatesParam; +} + +STACK_OF(X509_CRL)* SignerConfig::GetX509CRLs() const +{ + if (IsInputCertChainNotEmpty() || IsInputCrlNotEmpty() || signer == nullptr) { + return x509CRLs; + } + return signer->GetCrls(); +} + +void SignerConfig::SetX509CRLs(STACK_OF(X509_CRL)* crls) +{ + x509CRLs = crls; +} + +std::vector SignerConfig::GetSignatureAlgorithms() const +{ + return signatureAlgorithms; +} + +void SignerConfig::SetSignatureAlgorithms(const std::vector& signatureAlgorithmsParam) +{ + signatureAlgorithms = signatureAlgorithmsParam; +} + +const std::map& SignerConfig::GetSignParamMap() const +{ + return signParamMap; +} + +void SignerConfig::FillParameters(const std::map& params) +{ + signParamMap = params; +} + +std::shared_ptr SignerConfig::GetSigner() +{ + if (signer == nullptr) { + SignerFactory factory; + LocalizationAdapter adapter(options); + signer = factory.GetSigner(adapter); + } + return signer; +} + +int SignerConfig::GetCompatibleVersion() const +{ + return compatibleVersion; +} + +void SignerConfig::SetCompatibleVersion(int compatibleVersionParam) +{ + compatibleVersion = compatibleVersionParam; +} + +bool SignerConfig::IsInputCertChainNotEmpty() const +{ + return certificates != nullptr; +} + +bool SignerConfig::IsInputCrlNotEmpty() const +{ + return x509CRLs != nullptr; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/hap/entity/include/block_head.h b/binary_sign_tool/hap/entity/include/block_head.h new file mode 100644 index 00000000..01cf8d0d --- /dev/null +++ b/binary_sign_tool/hap/entity/include/block_head.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGNATRUETOOLS_BLOCK_HEAD_H +#define SIGNATRUETOOLS_BLOCK_HEAD_H + +#include +#include + +namespace OHOS { +namespace SignatureTools { +class BlockHead { +public: + static const int BLOCK_LEN = 8; + static const int ELF_BLOCK_LEN = 12; + static const int BIT_SIZE = 8; + static const int DOUBLE_BIT_SIZE = 16; + static const int TRIPLE_BIT_SIZE = 24; + static const int32_t SIGN_HEAD_LEN = 32; + +public: + static int GetBlockLen(); + static int GetElfBlockLen(); + static std::string GetBlockHead(const char type, const char tag, const short length, const int offset); + static std::vector GetBlockHeadLittleEndian(const char type, const char tag, + const int length, const int offset); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif \ No newline at end of file diff --git a/binary_sign_tool/hap/entity/include/content_digest_algorithm.h b/binary_sign_tool/hap/entity/include/content_digest_algorithm.h new file mode 100644 index 00000000..71591f63 --- /dev/null +++ b/binary_sign_tool/hap/entity/include/content_digest_algorithm.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATURETOOLS_CONTENT_DIGEST_ALGORITHM_H +#define SIGNATURETOOLS_CONTENT_DIGEST_ALGORITHM_H +#include + +namespace OHOS { +namespace SignatureTools { +// content digest algorithm +class ContentDigestAlgorithm { +public: + static const ContentDigestAlgorithm SHA256; + static const ContentDigestAlgorithm SHA384; + static const ContentDigestAlgorithm SHA512; + + ContentDigestAlgorithm(); + ContentDigestAlgorithm(const ContentDigestAlgorithm& other); + ContentDigestAlgorithm(const std::string& digestAlgorithm, const int digestOutputByteSize); + ContentDigestAlgorithm& operator=(const ContentDigestAlgorithm& other); + + std::string GetDigestAlgorithm(); + int GetDigestOutputByteSize(); + +private: + std::string m_digestAlgorithm; + int m_digestOutputByteSize; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATURETOOLS_CONTENT_DIGEST_ALGORITHM_H \ No newline at end of file diff --git a/binary_sign_tool/hap/entity/include/param_constants.h b/binary_sign_tool/hap/entity/include/param_constants.h new file mode 100644 index 00000000..2afcc113 --- /dev/null +++ b/binary_sign_tool/hap/entity/include/param_constants.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATURETOOLS_PARAM_CONSTANTS_H +#define SIGNATURETOOLS_PARAM_CONSTANTS_H +#include + +namespace OHOS { +namespace SignatureTools { +class ParamConstants { +public: + const static int HAP_FORMAT_ERROR = 20001; + const static int HAP_PARSE_ERROR = 20002; + const static int HAP_SIGNATURE_ERROR = 20003; + const static int HAP_SIGNATURE_NOT_FOUND_ERROR = 20004; + static const std::string HAP_SIG_SCHEME_V256_DIGEST_ALGORITHM; + static const std::string HAP_SIG_SCHEME_V384_DIGEST_ALGORITHM; + static const std::string HAP_SIG_SCHEME_V512_DIGEST_ALGORITHM; + static const std::string HAP_SIG_ALGORITHM_SHA256_ECDSA; + static const std::string HAP_SIG_ALGORITHM_SHA384_ECDSA; + static const std::string HAP_SIG_ALGORITHM_SHA512_ECDSA; + static const std::string ALIGNMENT; + static const std::string PARAM_SIGN_MODE; + static const std::string PARAM_BASIC_CRL; + static const std::string PARAM_BASIC_PROPERTY; + static const std::string PARAM_BASIC_PROFILE; + static const std::string PARAM_PROFILE_JSON_CONTENT; + static const std::string PARAM_BASIC_PROOF; + static const std::string PARAM_BASIC_ALIGNMENT; + static const std::string PARAM_BASIC_PRIVATE_KEY; + static const std::string PARAM_BASIC_INPUT_FILE; + static const std::string PARAM_BASIC_OUTPUT_FILE; + static const std::string PARAM_BASIC_SIGANTURE_ALG; + static const std::string PARAM_BASIC_PROFILE_SIGNED; + static const std::string PARAM_BASIC_COMPATIBLE_VERSION; + static const std::string PARAM_REMOTE_SERVER; + static const std::string PARAM_REMOTE_USERNAME; + static const std::string PARAM_REMOTE_USERPWD; + static const std::string PARAM_REMOTE_CODE; + static const std::string PARAM_REMOTE_ONLINEAUTHMODE; + static const std::string PARAM_REMOTE_SIGNERPLUGIN; + static const std::string PARAM_LOCAL_JKS_KEYSTORE; + static const std::string PARAM_LOCAL_JKS_KEYSTORE_CODE; + static const std::string PARAM_LOCAL_JKS_KEYALIAS_CODE; + static const std::string PARAM_LOCAL_PUBLIC_CERT; + static const std::string PARAM_VERIFY_CERTCHAIN_FILE; + static const std::string PARAM_VERIFY_PROFILE_FILE; + static const std::string PARAM_VERIFY_PROOF_FILE; + static const std::string PARAM_VERIFY_PROPERTY_FILE; + static const std::string PARAM_RESIGN_CONFIG_FILE; + static const std::string PARAM_IN_FORM; + static const std::string PARAM_SIGN_CODE; + static const std::string PARAM_AD_HOC; + static const std::string PARAM_MODULE_FILE; + static constexpr int FILE_NAME_MIN_LENGTH = 2; + static const std::string DISABLE_SIGN_CODE; + static const std::string ENABLE_SIGN_CODE; + static const std::string AD_HOC_TYPE_0; + static const std::string AD_HOC_TYPE_1; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATURETOOLS_PARAM_CONSTANTS_H diff --git a/binary_sign_tool/hap/entity/include/signature_algorithm_helper.h b/binary_sign_tool/hap/entity/include/signature_algorithm_helper.h new file mode 100644 index 00000000..ac957c5d --- /dev/null +++ b/binary_sign_tool/hap/entity/include/signature_algorithm_helper.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATURETOOLS_SIGNATUR_ALGORITHM_H +#define SIGNATURETOOLS_SIGNATUR_ALGORITHM_H +#include +#include // for std::pair + +#include "content_digest_algorithm.h" + +namespace OHOS { +namespace SignatureTools { +enum class SignatureAlgorithmId { + ECDSA_WITH_SHA256 = 0x201, + ECDSA_WITH_SHA384 = 0x202, + ECDSA_WITH_SHA512 = 0x203, + DSA_WITH_SHA256 = 0x301, + DSA_WITH_SHA384 = 0x302, + DSA_WITH_SHA512 = 0x303 +}; + +class SignatureAlgorithmHelper { +public: + static const SignatureAlgorithmHelper ECDSA_WITH_SHA256_INSTANCE; + static const SignatureAlgorithmHelper ECDSA_WITH_SHA384_INSTANCE; + + SignatureAlgorithmHelper(); + SignatureAlgorithmHelper(const SignatureAlgorithmHelper& other); + SignatureAlgorithmHelper(const SignatureAlgorithmId &id_, const std::string &keyAlg_, + const ContentDigestAlgorithm& digestAlg_, + const std::pair& sigParams_); + SignatureAlgorithmHelper& operator=(const SignatureAlgorithmHelper& other); + ~SignatureAlgorithmHelper(); + + static const SignatureAlgorithmHelper* FindById(const SignatureAlgorithmId id); + + SignatureAlgorithmId m_id; + std::string m_keyAlgorithm; + ContentDigestAlgorithm m_contentDigestAlgorithm; + std::pair m_signatureAlgAndParams; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_SIGNER_CONFIG_H \ No newline at end of file diff --git a/binary_sign_tool/hap/entity/src/content_digest_algorithm.cpp b/binary_sign_tool/hap/entity/src/content_digest_algorithm.cpp new file mode 100644 index 00000000..2a70b365 --- /dev/null +++ b/binary_sign_tool/hap/entity/src/content_digest_algorithm.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "content_digest_algorithm.h" +namespace OHOS { +namespace SignatureTools { +const ContentDigestAlgorithm ContentDigestAlgorithm::SHA256("SHA-256", 256 / 8); +const ContentDigestAlgorithm ContentDigestAlgorithm::SHA384("SHA-384", 384 / 8); +const ContentDigestAlgorithm ContentDigestAlgorithm::SHA512("SHA-512", 512 / 8); + +ContentDigestAlgorithm::ContentDigestAlgorithm() + : m_digestAlgorithm(""), + m_digestOutputByteSize(0) +{ +} + +ContentDigestAlgorithm::ContentDigestAlgorithm(const std::string& digestAlgorithm, + const int digestOutputByteSize) + : m_digestAlgorithm(digestAlgorithm), m_digestOutputByteSize(digestOutputByteSize) +{ +} + +ContentDigestAlgorithm::ContentDigestAlgorithm(const ContentDigestAlgorithm& other) + : m_digestAlgorithm(other.m_digestAlgorithm), + m_digestOutputByteSize(other.m_digestOutputByteSize) +{ +} + +ContentDigestAlgorithm& ContentDigestAlgorithm::operator=(const ContentDigestAlgorithm& other) +{ + if (this != &other) { + m_digestAlgorithm = other.m_digestAlgorithm; + m_digestOutputByteSize = other.m_digestOutputByteSize; + } + return *this; +} + +std::string ContentDigestAlgorithm::GetDigestAlgorithm() +{ + return m_digestAlgorithm; +} + +int ContentDigestAlgorithm::GetDigestOutputByteSize() +{ + return m_digestOutputByteSize; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/hap/entity/src/param_constants.cpp b/binary_sign_tool/hap/entity/src/param_constants.cpp new file mode 100644 index 00000000..fe48cf05 --- /dev/null +++ b/binary_sign_tool/hap/entity/src/param_constants.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "param_constants.h" + +namespace OHOS { +namespace SignatureTools { +const std::string ParamConstants::HAP_SIG_SCHEME_V256_DIGEST_ALGORITHM = "SHA-256"; +const std::string ParamConstants::HAP_SIG_SCHEME_V384_DIGEST_ALGORITHM = "SHA-384"; +const std::string ParamConstants::HAP_SIG_SCHEME_V512_DIGEST_ALGORITHM = "SHA-512"; +const std::string ParamConstants::HAP_SIG_ALGORITHM_SHA256_ECDSA = "SHA256withECDSA"; +const std::string ParamConstants::HAP_SIG_ALGORITHM_SHA384_ECDSA = "SHA384withECDSA"; +const std::string ParamConstants::HAP_SIG_ALGORITHM_SHA512_ECDSA = "SHA512withECDSA"; +const std::string ParamConstants::ALIGNMENT = "4"; +const std::string ParamConstants::PARAM_SIGN_MODE = "mode"; +const std::string ParamConstants::PARAM_BASIC_CRL = "crl"; +const std::string ParamConstants::PARAM_BASIC_PROPERTY = "property"; +const std::string ParamConstants::PARAM_BASIC_PROFILE = "profileFile"; +const std::string ParamConstants::PARAM_PROFILE_JSON_CONTENT = "profileContent"; +const std::string ParamConstants::PARAM_BASIC_PROOF = "proof"; +const std::string ParamConstants::PARAM_BASIC_ALIGNMENT = "a"; +const std::string ParamConstants::PARAM_BASIC_PRIVATE_KEY = "keyAlias"; +const std::string ParamConstants::PARAM_BASIC_INPUT_FILE = "inFile"; +const std::string ParamConstants::PARAM_BASIC_OUTPUT_FILE = "outFile"; +const std::string ParamConstants::PARAM_BASIC_SIGANTURE_ALG = "signAlg"; +const std::string ParamConstants::PARAM_BASIC_PROFILE_SIGNED = "profileSigned"; +const std::string ParamConstants::PARAM_BASIC_COMPATIBLE_VERSION = "compatibleVersion"; +const std::string ParamConstants::PARAM_REMOTE_SERVER = "signServer"; +const std::string ParamConstants::PARAM_REMOTE_USERNAME = "username"; +const std::string ParamConstants::PARAM_REMOTE_USERPWD = "userPwd"; +const std::string ParamConstants::PARAM_REMOTE_CODE = "password"; +const std::string ParamConstants::PARAM_REMOTE_ONLINEAUTHMODE = "onlineAuthMode"; +const std::string ParamConstants::PARAM_REMOTE_SIGNERPLUGIN = "signerPlugin"; +const std::string ParamConstants::PARAM_LOCAL_JKS_KEYSTORE = "keystoreFile"; +const std::string ParamConstants::PARAM_LOCAL_JKS_KEYSTORE_CODE = "keystorePwd"; +const std::string ParamConstants::PARAM_LOCAL_JKS_KEYALIAS_CODE = "keyPwd"; +const std::string ParamConstants::PARAM_LOCAL_PUBLIC_CERT = "appCertFile"; +const std::string ParamConstants::PARAM_VERIFY_CERTCHAIN_FILE = "outCertChain"; +const std::string ParamConstants::PARAM_VERIFY_PROFILE_FILE = "outProfile"; +const std::string ParamConstants::PARAM_VERIFY_PROOF_FILE = "outproof"; +const std::string ParamConstants::PARAM_VERIFY_PROPERTY_FILE = "outproperty"; +const std::string ParamConstants::PARAM_RESIGN_CONFIG_FILE = "resignconfig"; +const std::string ParamConstants::PARAM_IN_FORM = "inForm"; +const std::string ParamConstants::PARAM_SIGN_CODE = "signCode"; +const std::string ParamConstants::PARAM_AD_HOC = "adHoc"; +const std::string ParamConstants::PARAM_MODULE_FILE = "moduleFile"; +const std::string ParamConstants::DISABLE_SIGN_CODE = "0"; +const std::string ParamConstants::ENABLE_SIGN_CODE = "1"; +const std::string ParamConstants::AD_HOC_TYPE_0 = "0"; +const std::string ParamConstants::AD_HOC_TYPE_1 = "1"; +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/hap/entity/src/signature_algorithm_helper.cpp b/binary_sign_tool/hap/entity/src/signature_algorithm_helper.cpp new file mode 100644 index 00000000..62f9abe7 --- /dev/null +++ b/binary_sign_tool/hap/entity/src/signature_algorithm_helper.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "signature_algorithm_helper.h" + +namespace OHOS { +namespace SignatureTools { +const SignatureAlgorithmHelper SignatureAlgorithmHelper::ECDSA_WITH_SHA256_INSTANCE{ + SignatureAlgorithmId::ECDSA_WITH_SHA256, "EC", ContentDigestAlgorithm::SHA256, + {"SHA256withECDSA", nullptr} }; + +const SignatureAlgorithmHelper SignatureAlgorithmHelper::ECDSA_WITH_SHA384_INSTANCE{ + SignatureAlgorithmId::ECDSA_WITH_SHA384, "EC", ContentDigestAlgorithm::SHA384, + {"SHA384withECDSA", nullptr} }; + +SignatureAlgorithmHelper::SignatureAlgorithmHelper() : m_id(SignatureAlgorithmId::ECDSA_WITH_SHA256), + m_keyAlgorithm(""), + m_contentDigestAlgorithm(ContentDigestAlgorithm::SHA256), + m_signatureAlgAndParams("", nullptr) +{ +} + +SignatureAlgorithmHelper::SignatureAlgorithmHelper(const SignatureAlgorithmHelper& other) : m_id(other.m_id), + m_keyAlgorithm(other.m_keyAlgorithm), + m_contentDigestAlgorithm(other.m_contentDigestAlgorithm), + m_signatureAlgAndParams(other.m_signatureAlgAndParams.first, nullptr) +{ +} + +SignatureAlgorithmHelper::SignatureAlgorithmHelper(const SignatureAlgorithmId& id_, const std::string& keyAlg_, + const ContentDigestAlgorithm& digestAlg_, + const std::pair& sigParams_) + : m_id(id_), m_keyAlgorithm(keyAlg_), m_contentDigestAlgorithm(digestAlg_), m_signatureAlgAndParams(sigParams_) +{ +} + +SignatureAlgorithmHelper& SignatureAlgorithmHelper::operator=(const SignatureAlgorithmHelper& other) +{ + if (this != &other) { + m_id = other.m_id; + m_keyAlgorithm = other.m_keyAlgorithm; + m_contentDigestAlgorithm = other.m_contentDigestAlgorithm; + m_signatureAlgAndParams.first = other.m_signatureAlgAndParams.first; + m_signatureAlgAndParams.second = other.m_signatureAlgAndParams.second; + } + return *this; +} + +SignatureAlgorithmHelper::~SignatureAlgorithmHelper() +{ +} + +const SignatureAlgorithmHelper* SignatureAlgorithmHelper::FindById(const SignatureAlgorithmId id) +{ + if (id == SignatureAlgorithmId::ECDSA_WITH_SHA256) return &ECDSA_WITH_SHA256_INSTANCE; + if (id == SignatureAlgorithmId::ECDSA_WITH_SHA384) return &ECDSA_WITH_SHA384_INSTANCE; + return nullptr; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/hap/provider/include/local_sign_provider.h b/binary_sign_tool/hap/provider/include/local_sign_provider.h new file mode 100644 index 00000000..2dc2e3da --- /dev/null +++ b/binary_sign_tool/hap/provider/include/local_sign_provider.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_LOCAL_SIGN_PROVIDER_H +#define SIGNATRUETOOLS_LOCAL_SIGN_PROVIDER_H + +#include "sign_provider.h" + +namespace OHOS { +namespace SignatureTools { +class LocalSignProvider : public SignProvider { +public: + LocalSignProvider() = default; + ~LocalSignProvider() = default; + std::optional GetCrl(); + bool CheckParams(Options* options); + +private: + bool CheckPublicKeyPath(); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_LOCAL_SIGN_PROVIDER_H \ No newline at end of file diff --git a/binary_sign_tool/hap/provider/include/remote_sign_provider.h b/binary_sign_tool/hap/provider/include/remote_sign_provider.h new file mode 100644 index 00000000..62ec9a17 --- /dev/null +++ b/binary_sign_tool/hap/provider/include/remote_sign_provider.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_REMOTE_SIGN_PROVIDER_H +#define SIGNATRUETOOLS_REMOTE_SIGN_PROVIDER_H + +#include + +#include "sign_provider.h" +#include "params.h" + +namespace OHOS { +namespace SignatureTools { +class RemoteSignProvider : public SignProvider { +public: + RemoteSignProvider() = default; + ~RemoteSignProvider() = default; + bool CheckParams(Options* options) override; + bool CheckInputCertMatchWithProfile(X509* inputCert, X509* certInProfile)const override; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_REMOTE_SIGN_PROVIDER_H \ No newline at end of file diff --git a/binary_sign_tool/hap/provider/include/sign_provider.h b/binary_sign_tool/hap/provider/include/sign_provider.h new file mode 100644 index 00000000..3f3e08b2 --- /dev/null +++ b/binary_sign_tool/hap/provider/include/sign_provider.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_SIGN_PROVIDER_H +#define SIGNATRUETOOLS_SIGN_PROVIDER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "options.h" +#include "signature_tools_errno.h" +#include "signature_tools_log.h" +#include "signer_config.h" +#include "param_constants.h" +#include "byte_buffer.h" +#include "hap_utils.h" +#include "pkcs7_data.h" +#include "profile_verify.h" +#include "signature_info.h" + +typedef std::tuple, std::shared_ptr, std::string> fileIOTuple; +namespace OHOS { +namespace SignatureTools { +class SignProvider { +public: + SignProvider() = default; + virtual ~SignProvider() = default; + bool Sign(Options* options); + bool SignElf(Options* options); + bool SetSignParams(Options* options, std::unordered_set& paramSet); + virtual std::optional GetCrl(); + virtual bool CheckParams(Options* options); + virtual bool CheckInputCertMatchWithProfile(X509* inputCert, X509* certInProfile)const; + +protected: + void CheckSignAlignment(); + X509* GetCertificate(const std::string& certificate)const; + std::string GetCertificateCN(X509* cert)const; + std::string FindProfileFromOptionalBlocks()const; + int CheckProfileValid(STACK_OF(X509)* inputCerts); + int CheckProfileInfo(const ProfileInfo& info, STACK_OF(X509)* inputCerts)const; + int LoadOptionalBlocks(); + std::vector optionalBlocks; + std::map signParams = std::map(); + +private: + bool InitSigerConfig(SignerConfig& signerConfig, STACK_OF(X509)* publicCerts, Options* options); + + bool CreateSignerConfigs(STACK_OF(X509)* certificates, const std::optional& crl, + Options* options, SignerConfig&); + + bool CheckSignatureAlg(); + int LoadOptionalBlock(const std::string& file, int type); + bool CheckFile(const std::string& filePath); + + int GetX509Certificates(Options* options, STACK_OF(X509)** ret); + int GetPublicCerts(Options* options, STACK_OF(X509)** ret); + int GetCertificateChainFromFile(const std::string& certChianFile, STACK_OF(X509)** ret); + int GetCertListFromFile(const std::string& certsFile, STACK_OF(X509)** ret); + +private: + static std::vector VALID_SIGN_ALG_NAME; + static constexpr int FOUR_BYTE = 4; + std::string profileContent; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_SIGN_PROVIDER_H \ No newline at end of file diff --git a/binary_sign_tool/hap/provider/src/local_sign_provider.cpp b/binary_sign_tool/hap/provider/src/local_sign_provider.cpp new file mode 100644 index 00000000..3b2508b0 --- /dev/null +++ b/binary_sign_tool/hap/provider/src/local_sign_provider.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "local_sign_provider.h" +#include "params.h" +#include "file_utils.h" + +namespace OHOS { +namespace SignatureTools { +std::optional LocalSignProvider::GetCrl() +{ + return std::optional(); +} + +bool LocalSignProvider::CheckParams(Options* options) +{ + if (!SignProvider::CheckParams(options)) { + SIGNATURE_TOOLS_LOGE("Parameter check failed !"); + return false; + } + std::vector paramFileds; + paramFileds.emplace_back(ParamConstants::PARAM_LOCAL_JKS_KEYSTORE); + paramFileds.emplace_back(ParamConstants::PARAM_LOCAL_JKS_KEYSTORE_CODE); + paramFileds.emplace_back(ParamConstants::PARAM_LOCAL_JKS_KEYALIAS_CODE); + std::unordered_set paramSet = Params::InitParamField(paramFileds); + if (!this->SetSignParams(options, paramSet)) { + return false; + } + if (!CheckPublicKeyPath()) { + SIGNATURE_TOOLS_LOGE("appCertFile Parameter check error !"); + return false; + } + return true; +} + +bool LocalSignProvider::CheckPublicKeyPath() +{ + bool flag = false; + std::string publicCertsFile = signParams[ParamConstants::PARAM_LOCAL_PUBLIC_CERT]; + flag = !FileUtils::IsValidFile(publicCertsFile); + if (flag) { + SIGNATURE_TOOLS_LOGE("%s", std::string(publicCertsFile + " is valid").c_str()); + return false; + } + std::ifstream publicKeyFile(publicCertsFile); + flag = !publicKeyFile.is_open(); + if (flag) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, publicCertsFile + " open failed "); + return false; + } + publicKeyFile.close(); + return true; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/hap/provider/src/remote_sign_provider.cpp b/binary_sign_tool/hap/provider/src/remote_sign_provider.cpp new file mode 100644 index 00000000..640c5d26 --- /dev/null +++ b/binary_sign_tool/hap/provider/src/remote_sign_provider.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "remote_sign_provider.h" + +namespace OHOS { +namespace SignatureTools { +bool RemoteSignProvider::CheckParams(Options* options) +{ + if (!SignProvider::CheckParams(options)) { + SIGNATURE_TOOLS_LOGE("SignProvider::Parameter check failed !"); + return false; + } + // The following code is for reference only. + std::vector paramFileds; + paramFileds.emplace_back(ParamConstants::PARAM_REMOTE_SERVER); + paramFileds.emplace_back(ParamConstants::PARAM_REMOTE_USERNAME); + paramFileds.emplace_back(ParamConstants::PARAM_REMOTE_USERPWD); + paramFileds.emplace_back(ParamConstants::PARAM_REMOTE_ONLINEAUTHMODE); + paramFileds.emplace_back(ParamConstants::PARAM_REMOTE_SIGNERPLUGIN); + std::unordered_set paramSet = Params::InitParamField(paramFileds); + for (auto it = options->begin(); it != options->end(); it++) { + if (paramSet.find(it->first) != paramSet.end()) { + size_t size = it->first.size(); + std::string str = it->first.substr(size - 3); + if (str == "Pwd") { + signParams.insert(std::make_pair(it->first, "")); + } else { + signParams.insert(std::make_pair(it->first, options->GetString(it->first))); + } + } + } + for (const auto& param : paramFileds) { + if (signParams.find(param) == signParams.end()) { + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, + "Missing parameter:" + param); + return false; + } + } + return true; +} + +bool RemoteSignProvider::CheckInputCertMatchWithProfile(X509* inputCert, X509* certInProfile) const +{ + bool ret = true; + if (inputCert == nullptr || certInProfile == nullptr) { + PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, + "The certificate is empty"); + return false; + } + X509_NAME* subject1 = X509_get_subject_name(inputCert); + X509_NAME* subject2 = X509_get_subject_name(certInProfile); + if (X509_NAME_cmp(subject1, subject2) != 0) { + PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, + "The subject does not match!"); + return false; + } + X509_NAME* issuer1 = X509_get_issuer_name(inputCert); + X509_NAME* issuer2 = X509_get_issuer_name(certInProfile); + if (X509_NAME_cmp(issuer1, issuer2) != 0) { + PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, + "The issuer name does not match!"); + return false; + } + ASN1_INTEGER* serial1 = X509_get_serialNumber(inputCert); + ASN1_INTEGER* serial2 = X509_get_serialNumber(certInProfile); + if (ASN1_INTEGER_cmp(serial1, serial2) != 0) { + PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, + "serial number does not match!"); + return false; + } + EVP_PKEY* pkey1 = X509_get_pubkey(inputCert); + EVP_PKEY* pkey2 = X509_get_pubkey(certInProfile); + if (pkey1 && pkey2 && EVP_PKEY_cmp(pkey1, pkey2) != 1) { + EVP_PKEY_free(pkey1); + EVP_PKEY_free(pkey2); + PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, + "The public key does not match!"); + return false; + } + if (!pkey1 || !pkey2) { + PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, + "The public key is null!"); + ret = false; + } + if (pkey1) EVP_PKEY_free(pkey1); + if (pkey2) EVP_PKEY_free(pkey2); + return ret; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/hap/provider/src/sign_provider.cpp b/binary_sign_tool/hap/provider/src/sign_provider.cpp new file mode 100644 index 00000000..35ff929a --- /dev/null +++ b/binary_sign_tool/hap/provider/src/sign_provider.cpp @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "sign_provider.h" +#include +#include +#include +#include +#include +#include + +#include "nlohmann/json.hpp" +#include "string_utils.h" +#include "file_utils.h" +#include "sign_elf.h" +#include "params.h" +#include "constant.h" + +using namespace nlohmann; +namespace OHOS { +namespace SignatureTools { +std::vector SignProvider::VALID_SIGN_ALG_NAME = { + ParamConstants::HAP_SIG_ALGORITHM_SHA256_ECDSA, + ParamConstants::HAP_SIG_ALGORITHM_SHA384_ECDSA, + ParamConstants::HAP_SIG_ALGORITHM_SHA512_ECDSA +}; + +bool SignProvider::InitSigerConfig(SignerConfig& signerConfig, STACK_OF(X509)* publicCerts, Options* options) +{ + std::optional crl = GetCrl(); + if (!CreateSignerConfigs(publicCerts, crl, options, signerConfig)) { + SIGNATURE_TOOLS_LOGE("[Sign] create Signer Configs failed"); + return false; + } + return true; +} + +bool SignProvider::SignElf(Options* options) +{ + STACK_OF(X509)* publicCerts = nullptr; + int ret = GetX509Certificates(options, &publicCerts); + if (ret != RET_OK) { + sk_X509_pop_free(publicCerts, X509_free); + SIGNATURE_TOOLS_LOGE("[SignElf] get X509 Certificates failed! errorCode:%d", ret); + return false; + } + SignerConfig signerConfig; + if (!InitSigerConfig(signerConfig, publicCerts, options)) { + SIGNATURE_TOOLS_LOGE("SignElf] create Signer Configs failed"); + return false; + } + + if (!profileContent.empty()) { + signParams.insert(std::make_pair(ParamConstants::PARAM_PROFILE_JSON_CONTENT, profileContent)); + } + + if (!SignElf::Sign(signerConfig, signParams)) { + SIGNATURE_TOOLS_LOGE("[SignElf] sign elf failed"); + return false; + } + + return true; +} + +bool SignProvider::CreateSignerConfigs(STACK_OF(X509)* certificates, const std::optional& crl, + Options* options, SignerConfig& inOut) +{ + inOut.FillParameters(signParams); + inOut.SetCertificates(certificates); + inOut.SetOptions(options); + std::vector signatureAlgorithms; + SignatureAlgorithmHelper alg; + // Since CheckParmaAndInitConfig has already validated all parameters, it is possible to directly use at + if (!Params::GetSignatureAlgorithm(signParams.at(ParamConstants::PARAM_BASIC_SIGANTURE_ALG), + alg)) { + SIGNATURE_TOOLS_LOGE("[Sign] get Signature Algorithm failed"); + return false; + } + signatureAlgorithms.push_back(alg); + inOut.SetSignatureAlgorithms(signatureAlgorithms); + if (crl.has_value()) { + SIGNATURE_TOOLS_LOGE("not support crl"); + return false; + } + return true; +} + +int SignProvider::LoadOptionalBlocks() +{ + int ret = RET_OK; + if (auto property = signParams.find(ParamConstants::PARAM_BASIC_PROPERTY); + property != signParams.end()) { + if ((ret = LoadOptionalBlock(property->second, HapUtils::HAP_PROPERTY_BLOCK_ID)) != RET_OK) + return ret; + } + if (auto profile = signParams.find(ParamConstants::PARAM_BASIC_PROFILE); profile != signParams.end()) { + if ((ret = LoadOptionalBlock(profile->second, HapUtils::HAP_PROFILE_BLOCK_ID)) != RET_OK) + return ret; + } + if (auto proofOfRotation = signParams.find(ParamConstants::PARAM_BASIC_PROOF); + proofOfRotation != signParams.end()) { + if ((LoadOptionalBlock(proofOfRotation->second, HapUtils::HAP_PROOF_OF_ROTATION_BLOCK_ID)) != RET_OK) + return ret; + } + return ret; +} + +int SignProvider::LoadOptionalBlock(const std::string& file, int type) +{ + if (file.empty()) + return RET_OK; + if (!CheckFile(file)) { + SIGNATURE_TOOLS_LOGE("check file failed. Invalid file: %s, file type: %d", + file.c_str(), type); + return FILE_NOT_FOUND; + } + ByteBuffer optionalBlockBuffer; + if (!FileUtils::ReadFileToByteBuffer(file, optionalBlockBuffer)) + return IO_ERROR; + if (optionalBlockBuffer.GetCapacity() == 0) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, file + " is empty!"); + return IO_ERROR; + } + optionalBlocks.push_back({type, optionalBlockBuffer}); + return RET_OK; +} + +std::optional SignProvider::GetCrl() +{ + return std::nullopt; +} + +bool SignProvider::CheckFile(const std::string& filePath) +{ + if (filePath.empty()) { + PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "file name is null."); + return false; + } + if (!std::filesystem::exists(filePath) || !std::filesystem::is_regular_file(filePath)) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, filePath + " not exist or can not read!"); + return false; + } + return true; +} + +int SignProvider::GetX509Certificates(Options* options, STACK_OF(X509)** X509Vec) +{ + int ret = RET_OK; + // 1.check the parameters + if (!CheckParams(options)) { + SIGNATURE_TOOLS_LOGE("Check Params failed please check"); + return COMMAND_ERROR; + } + // 2.get x509 verify certificate + ret = GetPublicCerts(options, X509Vec); + if (ret != RET_OK) { + SIGNATURE_TOOLS_LOGE("Get Public Certs please check"); + return ret; + } + // 3. load optionalBlocks + ret = LoadOptionalBlocks(); + if (ret != RET_OK) { + SIGNATURE_TOOLS_LOGE("Load Optional Blocks please check"); + return ret; + } + std::string profileFile = options->GetString(Options::PROFILE_FILE); + if (FileUtils::IsEmpty(profileFile)) { + return ret; + } + // 4. check Profile Valid + if ((ret = CheckProfileValid(*X509Vec)) < 0) { + SIGNATURE_TOOLS_LOGE("profile check error"); + sk_X509_pop_free(*X509Vec, X509_free); + *X509Vec = nullptr; + return ret; + } + return ret; +} + +int SignProvider::GetPublicCerts(Options* options, STACK_OF(X509)** ret) +{ + std::string appCertFileName = options->GetString(Options::APP_CERT_FILE); + if (appCertFileName.empty()) { + SIGNATURE_TOOLS_LOGI("appCertFile param can not find,may be is RemoteSigner"); + return RET_OK; + } + return GetCertificateChainFromFile(appCertFileName, ret); +} + +int SignProvider::GetCertificateChainFromFile(const std::string& certChianFile, STACK_OF(X509)** ret) +{ + return GetCertListFromFile(certChianFile, ret); +} + +int SignProvider::GetCertListFromFile(const std::string& certsFile, STACK_OF(X509)** ret) +{ + X509* cert = nullptr; + *ret = sk_X509_new(nullptr); + if (*ret == nullptr) { + PrintErrorNumberMsg("RET_FAILED", RET_FAILED, "get CertList FromFile [sk_X509_new] failed"); + return RET_FAILED; + } + BIO* certBio = BIO_new_file(certsFile.c_str(), "rb"); + if (!certBio) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, + std::string("get CertList from file ") + certsFile + " failed"); + sk_X509_free(*ret); + return IO_ERROR; + } + while (1) { + cert = PEM_read_bio_X509(certBio, NULL, NULL, NULL); + if (cert == nullptr) + break; + sk_X509_push(*ret, cert); + } + BIO_free(certBio); + return RET_OK; +} + +bool SignProvider::SetSignParams(Options* options, std::unordered_set& paramSet) +{ + for (auto it = options->begin(); it != options->end(); it++) { + if (paramSet.find(it->first) != paramSet.end()) { + size_t size = it->first.size(); + std::string str = it->first.substr(size - 3); + if (str != "Pwd") { + this->signParams.insert(std::make_pair(it->first, options->GetString(it->first))); + } + } + } + return true; +} + +bool SignProvider::CheckParams(Options* options) +{ + std::vector paramFileds; + paramFileds.emplace_back(ParamConstants::PARAM_BASIC_ALIGNMENT); + paramFileds.emplace_back(ParamConstants::PARAM_BASIC_SIGANTURE_ALG); + paramFileds.emplace_back(ParamConstants::PARAM_BASIC_INPUT_FILE); + paramFileds.emplace_back(ParamConstants::PARAM_BASIC_OUTPUT_FILE); + paramFileds.emplace_back(ParamConstants::PARAM_BASIC_PRIVATE_KEY); + paramFileds.emplace_back(ParamConstants::PARAM_BASIC_PROFILE); + paramFileds.emplace_back(ParamConstants::PARAM_BASIC_PROOF); + paramFileds.emplace_back(ParamConstants::PARAM_BASIC_PROPERTY); + paramFileds.emplace_back(ParamConstants::PARAM_REMOTE_SERVER); + paramFileds.emplace_back(ParamConstants::PARAM_BASIC_PROFILE_SIGNED); + paramFileds.emplace_back(ParamConstants::PARAM_LOCAL_PUBLIC_CERT); + paramFileds.emplace_back(ParamConstants::PARAM_SIGN_CODE); + paramFileds.emplace_back(ParamConstants::PARAM_MODULE_FILE); + paramFileds.emplace_back(ParamConstants::PARAM_AD_HOC); + + std::unordered_set paramSet = Params::InitParamField(paramFileds); + for (auto it = options->begin(); it != options->end(); it++) { + if (paramSet.find(it->first) != paramSet.end()) { + signParams.insert(std::make_pair(it->first, options->GetString(it->first))); + } + } + + if (signParams.find(ParamConstants::PARAM_BASIC_PROFILE_SIGNED) == signParams.end() + || signParams.at(ParamConstants::PARAM_BASIC_PROFILE_SIGNED).empty()) { + signParams[ParamConstants::PARAM_BASIC_PROFILE_SIGNED] = DEFAULT_PROFILE_SIGNED_1; + } + if (signParams.find(ParamConstants::PARAM_AD_HOC) == signParams.end() + || signParams.at(ParamConstants::PARAM_AD_HOC).empty()) { + signParams[ParamConstants::PARAM_AD_HOC] = ParamConstants::AD_HOC_TYPE_0; + } + if (!CheckSignatureAlg()) { + SIGNATURE_TOOLS_LOGE("signAlg Parameter is not support"); + return false; + } + CheckSignAlignment(); + return true; +} + +bool SignProvider::CheckSignatureAlg() +{ + std::string signAlg = signParams[ParamConstants::PARAM_BASIC_SIGANTURE_ALG]; + // Remove leading spaces + size_t start = signAlg.find_first_not_of(" "); + if (start != std::string::npos) { + signAlg = signAlg.substr(start); + } + // Remove trailing spaces + size_t end = signAlg.find_last_not_of(" "); + if (end != std::string::npos) { + signAlg.resize(end + 1); + } + for (auto it = VALID_SIGN_ALG_NAME.begin(); it != VALID_SIGN_ALG_NAME.end(); it++) { + if (StringUtils::CaseCompare(*it, signAlg)) { + return true; + } + } + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, + "signAlg Parameter is only support [SHA256withECDSA / SHA384withECDSA]"); + return false; +} + +void SignProvider::CheckSignAlignment() +{ + if (signParams.find(ParamConstants::PARAM_BASIC_ALIGNMENT) == signParams.end()) { + signParams.insert(std::make_pair(ParamConstants::PARAM_BASIC_ALIGNMENT, ParamConstants::ALIGNMENT)); + } +} + +X509* SignProvider::GetCertificate(const std::string& certificate)const +{ + BIO* in = BIO_new_mem_buf(certificate.data(), certificate.size()); + if (!in) { + PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, + "bio new error ,get ceritificate from base64 certificate failed"); + return NULL; + } + X509* cert = NULL; + cert = PEM_read_bio_X509(in, NULL, NULL, NULL); + if (!cert) { + BIO_free(in); + PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, + "read no cert from base64 certificate failed"); + return NULL; + } + BIO_free(in); + return cert; +} + +std::string SignProvider::GetCertificateCN(X509* cert)const +{ + X509_NAME* name = NULL; + int len = 0; + std::string ret; + if (cert == NULL) { + return ""; + } + name = X509_get_subject_name(cert); + if (!name) { + SIGNATURE_TOOLS_LOGE("name is NULL,get X509_NAME from cert failed"); + } + len = X509_NAME_get_text_by_NID(name, NID_countryName, NULL, 0); + if (len <= 0) { + return ""; + } + ret.resize(len + 1); + if (X509_NAME_get_text_by_NID(name, NID_countryName, &ret[0], len + 1) != len) { + return ""; + } + return ret; +} + +std::string SignProvider::FindProfileFromOptionalBlocks()const +{ + std::string profile; + for (const OptionalBlock& optionalBlock : optionalBlocks) { + if (optionalBlock.optionalType == HapUtils::HAP_PROFILE_BLOCK_ID) { + profile = std::string(optionalBlock.optionalBlockValue.GetBufferPtr(), + optionalBlock.optionalBlockValue.GetCapacity()); + } + } + return profile; +} + +int SignProvider::CheckProfileValid(STACK_OF(X509)* inputCerts) +{ + std::string profile = FindProfileFromOptionalBlocks(); + std::map::const_iterator ite = + signParams.find(ParamConstants::PARAM_BASIC_PROFILE_SIGNED); + if (ite == signParams.end()) { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, + "find PARAM_BASIC_PROFILE_SIGNED failed"); + return INVALIDPARAM_ERROR; + } + bool isProfileWithoutSign = (DEFAULT_PROFILE_SIGNED_0 == ite->second); + if (!isProfileWithoutSign) { + PKCS7Data p7Data; + if (p7Data.Parse(profile) < 0) { + SIGNATURE_TOOLS_LOGE("Parse profile error."); + return PARSE_ERROR; + } + if (p7Data.Verify() < 0) { + SIGNATURE_TOOLS_LOGE("Verify profile pkcs7 failed! Profile is invalid."); + return VERIFY_ERROR; + } + profileContent.clear(); + if (p7Data.GetContent(profileContent) < 0) { + SIGNATURE_TOOLS_LOGE("get content data failed"); + return INVALIDPARAM_ERROR; + } + } else { + profileContent = profile; + } + + ProfileInfo info; + if (ParseProvision(profileContent, info) != PROVISION_OK) { + SIGNATURE_TOOLS_LOGE("parse provision error"); + return PARSE_ERROR; + } + if (CheckProfileInfo(info, inputCerts) < 0) { + SIGNATURE_TOOLS_LOGE("Check Profile Info error"); + return RET_FAILED; + } + return 0; +} + +int SignProvider::CheckProfileInfo(const ProfileInfo& info, STACK_OF(X509)* inputCerts)const +{ + X509* certInProfile = NULL; + if (info.type == ProvisionType::RELEASE) { + certInProfile = GetCertificate(info.bundleInfo.distributionCertificate); + } else if (info.type == ProvisionType::DEBUG) { + certInProfile = GetCertificate(info.bundleInfo.developmentCertificate); + } else { + PrintErrorNumberMsg("NOT_SUPPORT_ERROR", NOT_SUPPORT_ERROR, "Unsupported profile type!"); + return NOT_SUPPORT_ERROR; + } + if (sk_X509_num(inputCerts) > 0 && !CheckInputCertMatchWithProfile(sk_X509_value(inputCerts, 0), + certInProfile)) { + X509_free(certInProfile); + SIGNATURE_TOOLS_LOGE("input certificates do not match with profile!"); + return RET_FAILED; + } + std::string cn = GetCertificateCN(certInProfile); + X509_free(certInProfile); + SIGNATURE_TOOLS_LOGI("certificate in profile: %s", cn.c_str()); + if (cn.empty()) { + PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, "Common name of certificate is empty!"); + return CERTIFICATE_ERROR; + } + return 0; +} + +bool SignProvider::CheckInputCertMatchWithProfile(X509* inputCert, X509* certInProfile)const +{ + return true; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/hap/sign/include/bc_pkcs7_generator.h b/binary_sign_tool/hap/sign/include/bc_pkcs7_generator.h new file mode 100644 index 00000000..64f8ce36 --- /dev/null +++ b/binary_sign_tool/hap/sign/include/bc_pkcs7_generator.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_BC_PKCS7_GENERATOR_GENERATOR_H +#define SIGNATRUETOOLS_BC_PKCS7_GENERATOR_GENERATOR_H + +#include +#include + +#include "pkcs7_generator.h" +#include "openssl/x509.h" +#include "signer_config.h" +#include "signer.h" + +namespace OHOS { +namespace SignatureTools { +class BCPkcs7Generator : public Pkcs7Generator { +public: + /** + * Generate PKCS#7 signed data with the specific content and signer config. + * + * @param content PKCS7 data, content of unsigned file digest. + * @param signerConfig configurations of signer. + * @ret PKCS7 signed data. + * @return 0:success <0:error + */ + virtual ~BCPkcs7Generator(); + int GenerateSignedData(const std::string& content, SignerConfig* signerConfig, std::string& ret) override; + static int GetSigAlg(SignerConfig* signerConfig, std::string& sigAlg); +private: + int PackagePKCS7(const std::string& content, const std::shared_ptr& signer, + const std::string& sigAlg, std::string& ret); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_BC_PKCS7_GENERATOR_GENERATOR_H \ No newline at end of file diff --git a/binary_sign_tool/hap/sign/include/pkcs7_generator.h b/binary_sign_tool/hap/sign/include/pkcs7_generator.h new file mode 100644 index 00000000..d0ae618c --- /dev/null +++ b/binary_sign_tool/hap/sign/include/pkcs7_generator.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_PKCS7_GENERATOR_GENERATOR_H +#define SIGNATRUETOOLS_PKCS7_GENERATOR_GENERATOR_H + +#include + +#include "signer_config.h" + +namespace OHOS { +namespace SignatureTools { + +class Pkcs7Generator { +public: + virtual ~Pkcs7Generator() = default; + /** + * Generate PKCS#7 signed data with the specific content and signer config. + * + * @param content PKCS7 data, content of unsigned file digest. + * @param signerConfig configurations of signer. + * @param ret PKCS7 signed data. + * @return 0:success <0:error + */ + virtual int GenerateSignedData(const std::string& content, SignerConfig* signerConfig, std::string& ret) = 0; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_PKCS7_GENERATOR_GENERATOR_H \ No newline at end of file diff --git a/binary_sign_tool/hap/sign/include/sign_elf.h b/binary_sign_tool/hap/sign/include/sign_elf.h new file mode 100644 index 00000000..6840d35d --- /dev/null +++ b/binary_sign_tool/hap/sign/include/sign_elf.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGNATRUETOOLS_SIGH_ELF_H +#define SIGNATRUETOOLS_SIGH_ELF_H + +#include +#include +#include +#include + +#include "signer_config.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { +class SignElf { +public: + static const char CODESIGN_BLOCK_TYPE = 3; + static bool Sign(SignerConfig& signerConfig, std::map &signParams); + +private: + static int blockNum; + static constexpr int FILE_PATH_LENGTH = 256; + static constexpr int PAGE_SIZE = 4096; + static constexpr int FILE_BUFFER_BLOCK = 16384; + static const std::string profileSec; + static const std::string permissionSec; + + static bool loadModule(std::map& signParams, std::string& moduleContent); + static bool loadProfileAndSign(SignerConfig& signerConfig, std::map& signParams, + std::string& p7b); + static bool isExecElf(ELFIO::elfio& reader); + static bool WriteCodeSignBlock(SignerConfig& signerConfig, const std::map& signParams, + long secOffset); + static bool WriteSection(ELFIO::elfio& reader, const std::string& content, const std::string& secName); + static bool WriteSecDataToFile(ELFIO::elfio& reader, SignerConfig& signerConfig, + std::map& signParams); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif diff --git a/binary_sign_tool/hap/sign/src/bc_pkcs7_generator.cpp b/binary_sign_tool/hap/sign/src/bc_pkcs7_generator.cpp new file mode 100644 index 00000000..ca7205b6 --- /dev/null +++ b/binary_sign_tool/hap/sign/src/bc_pkcs7_generator.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include + +#include "constant.h" +#include "bc_pkcs7_generator.h" +#include "signature_tools_log.h" +#include "pkcs7_data.h" +#include "signature_algorithm_helper.h" +#include "signer_config.h" +#include "signature_tools_errno.h" + +namespace OHOS { +namespace SignatureTools { +BCPkcs7Generator::~BCPkcs7Generator() +{ +} +int BCPkcs7Generator::GenerateSignedData(const std::string& content, + SignerConfig* signerConfig, std::string& ret) +{ + int result = RET_OK; + std::string sigAlg; + if (content.empty()) { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, + "digest content is empty, generate signed data failed"); + return INVALIDPARAM_ERROR; + } + if (signerConfig == NULL) { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, "signerConfig is NULL"); + return INVALIDPARAM_ERROR; + } + std::shared_ptr signer(signerConfig->GetSigner()); + if (signer == NULL) { + SIGNATURE_TOOLS_LOGE("signer is NULL"); + return INVALIDPARAM_ERROR; + } + result = GetSigAlg(signerConfig, sigAlg); + if (result < 0) { + SIGNATURE_TOOLS_LOGE("get sigAlg from signerConfig failed"); + return result; + } + result = PackagePKCS7(content, signer, sigAlg, ret); + if (result < 0) { + SIGNATURE_TOOLS_LOGE("package pkcs7 failed!"); + return result; + } + return result; +} +int BCPkcs7Generator::PackagePKCS7(const std::string& content, const std::shared_ptr& signer, + const std::string& sigAlg, std::string& ret) +{ + PKCS7Data p7Data; + int result = RET_OK; + result = p7Data.Sign(content, signer, sigAlg, ret); + if (result < 0) { + SIGNATURE_TOOLS_LOGE("generate pkcs7 block failed"); + return SIGN_ERROR; + } + result = p7Data.Parse(ret); + if (result < 0) { + SIGNATURE_TOOLS_LOGE("parse pkcs7 bytes failed"); + return PARSE_ERROR; + } + result = p7Data.Verify(); + if (result < 0) { + SIGNATURE_TOOLS_LOGE("verify pkcs7 block failed"); + return VERIFY_ERROR; + } + return result; +} + +int BCPkcs7Generator::GetSigAlg(SignerConfig* signerConfig, std::string& sigAlg) +{ + std::vector sigs = signerConfig->GetSignatureAlgorithms(); + if (sigs.size() != 1) { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, "sigAlg count not equal to 1"); + return INVALIDPARAM_ERROR; + } + SignatureAlgorithmHelper signatureAlg = sigs[0]; + if (signatureAlg.m_id == SignatureAlgorithmId::ECDSA_WITH_SHA256) { + sigAlg = SIGN_ALG_SHA256; + } else if (signatureAlg.m_id == SignatureAlgorithmId::ECDSA_WITH_SHA384) { + sigAlg = SIGN_ALG_SHA384; + } else { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, + sigAlg + "is invalid sigAlg, please use SHA256withECDSA/SHA384withECDSA, sign failed"); + return NOT_SUPPORT_ERROR; + } + return RET_OK; +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/hap/sign/src/sign_elf.cpp b/binary_sign_tool/hap/sign/src/sign_elf.cpp new file mode 100644 index 00000000..c93feaec --- /dev/null +++ b/binary_sign_tool/hap/sign/src/sign_elf.cpp @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sign_elf.h" +#include +#include + +#include "file_utils.h" +#include "string_utils.h" +#include "constant.h" +#include "param_constants.h" +#include "profile_sign_tool.h" + +namespace OHOS { +namespace SignatureTools { + +int SignElf::blockNum = 0; +const std::string SignElf::profileSec = ".profile"; +const std::string SignElf::permissionSec = ".permission"; + +bool SignElf::Sign(SignerConfig& signerConfig, std::map& signParams) +{ + std::string inputFile = signParams.at(ParamConstants::PARAM_BASIC_INPUT_FILE); + ELFIO::elfio elfReader; + if (!elfReader.load(inputFile)) { + SIGNATURE_TOOLS_LOGE("[SignElf] Failed to load input ELF file"); + return false; + } + bool writeProfilFlag = WriteSecDataToFile(elfReader, signerConfig, signParams); + if (!writeProfilFlag) { + SIGNATURE_TOOLS_LOGE("[SignElf] WriteSecDataToFile error"); + return false; + } + std::string outputFile = signParams.at(ParamConstants::PARAM_BASIC_OUTPUT_FILE); + std::string tmpOutputFilePath = outputFile; + if (outputFile == inputFile) { + tmpOutputFilePath = "tmp-signed-elf"; + } + if (!elfReader.save(tmpOutputFilePath)) { + SIGNATURE_TOOLS_LOGE("[SignElf] Failed to save out ELF file"); + return false; + } + return FileUtils::CopyTmpFileAndDel(tmpOutputFilePath, outputFile); +} + +bool SignElf::loadModule(std::map& signParams, std::string& moduleContent) +{ + if (signParams.find(ParamConstants::PARAM_MODULE_FILE) != signParams.end()) { + std::string modulefilePath = signParams.at(ParamConstants::PARAM_MODULE_FILE); + if (FileUtils::ReadFile(modulefilePath, moduleContent) < 0) { + SIGNATURE_TOOLS_LOGE("[SignElf] Failed to open module file"); + return false; + } + } else { + SIGNATURE_TOOLS_LOGE("[SignElf] Failed to find module file"); + return false; + } + return true; +} + +bool SignElf::loadProfileAndSign(SignerConfig& signerConfig, std::map& signParams, + std::string& p7b) +{ + std::string profileContent; + if (signParams.find(ParamConstants::PARAM_BASIC_PROFILE) != signParams.end()) { + std::string profilefilePath = signParams.at(ParamConstants::PARAM_BASIC_PROFILE); + if (FileUtils::ReadFile(profilefilePath, profileContent) < 0) { + SIGNATURE_TOOLS_LOGE("[SignElf] Failed to open profile file"); + return false; + } + } else { + SIGNATURE_TOOLS_LOGE("[SignElf] Failed to find profile file"); + return false; + } + std::string profileSigned = signParams.at(ParamConstants::PARAM_BASIC_PROFILE_SIGNED); + if (profileSigned == DEFAULT_PROFILE_SIGNED_0) { + std::string alg = signParams.at(ParamConstants::PARAM_BASIC_SIGANTURE_ALG); + if (ProfileSignTool::SignProfile(profileContent, signerConfig.GetSigner(), alg, p7b) < 0) { + SIGNATURE_TOOLS_LOGE("[SignElf] SignProfile error"); + return false; + } + } else { + p7b = profileContent; + } + return true; +} + +bool SignElf::isExecElf(ELFIO::elfio& reader) +{ + ELFIO::Elf64_Half eType = reader.get_type(); + if (eType == ELFIO::ET_EXEC) { + return true; + } + if (eType == ELFIO::ET_DYN && reader.get_entry() > 0) { + return true; + } + return false; +} + +bool SignElf::WriteCodeSignBlock(SignerConfig& signerConfig, const std::map& signParams, + long secOffset) +{ + std::string inputFile = signParams.at(ParamConstants::PARAM_BASIC_INPUT_FILE); + std::string outputFile = signParams.at(ParamConstants::PARAM_BASIC_OUTPUT_FILE); + + ELFIO::elfio reader; + if (!reader.load(inputFile)) { + SIGNATURE_TOOLS_LOGE("[SignElf] Failed to load input ELF file"); + return false; + } + + // Create .codesign section with 4K size + ELFIO::section* codesignSec = reader.sections.add(".codesign"); + if (!codesignSec) { + SIGNATURE_TOOLS_LOGE("[SignElf] Failed to create .codesign section"); + return false; + } + + codesignSec->set_type(ELFIO::SHT_PROGBITS); + codesignSec->set_flags(ELFIO::SHF_ALLOC); + codesignSec->set_addr_align(1); + + // Allocate 4K of data + const size_t codesignSize = 4096; + std::vector codesignData(codesignSize, 0); + + codesignSec->set_data(codesignData.data(), codesignData.size()); + + // Save the modified ELF file + if (!reader.save(outputFile)) { + SIGNATURE_TOOLS_LOGE("[SignElf] Failed to save output ELF file"); + return false; + } + + // Get the offset of the .codesign section + ELFIO::Elf64_Off sectionOffset = codesignSec->get_offset(); + SIGNATURE_TOOLS_LOGI("[SignElf] .codesign section offset: %ld", sectionOffset); + secOffset = sectionOffset; + return true; +} + +bool SignElf::WriteSection(ELFIO::elfio& reader, const std::string& content, const std::string& secName) +{ + ELFIO::section* sec = reader.sections[secName]; + if (sec) { + SIGNATURE_TOOLS_LOGE("[SignElf] %s section already exists", secName.c_str()); + return false; + } + sec = reader.sections.add(secName); + if (!sec) { + SIGNATURE_TOOLS_LOGE("[SignElf] Failed to create %s section", secName.c_str()); + return false; + } + sec->set_type(ELFIO::SHT_PROGBITS); + sec->set_flags(ELFIO::SHF_ALLOC); + sec->set_addr_align(1); + sec->set_data(content); + return true; +} + +bool SignElf::WriteSecDataToFile(ELFIO::elfio& reader, SignerConfig& signerConfig, + std::map& signParams) +{ + // check elf bin or so + if (!isExecElf(reader)) { + return true; + } + std::string p7b; + if (!loadProfileAndSign(signerConfig, signParams, p7b)) { + return false; + } + if (!WriteSection(reader, p7b, profileSec)) { + return false; + } + PrintMsg("add profile to ELF file success"); + std::string moduleContent; + if (!loadModule(signParams, moduleContent)) { + return false; + } + if (!WriteSection(reader, moduleContent, permissionSec)) { + return false; + } + PrintMsg("add permission to ELF file success"); + return true; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/hap/signature_tools_hap.gni b/binary_sign_tool/hap/signature_tools_hap.gni new file mode 100644 index 00000000..6069ded5 --- /dev/null +++ b/binary_sign_tool/hap/signature_tools_hap.gni @@ -0,0 +1,35 @@ +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("../signature_tools.gni") +signature_tools_hap_include = [ + "${signature_tools_hap}/verify/include", + "${signature_tools_hap}/config/include", + "${signature_tools_hap}/entity/include", + "${signature_tools_hap}/provider/include", + "${signature_tools_hap}/sign/include", + "${signature_tools_hap}/utils/include", +] + +signature_tools_hap_src = [ + "${signature_tools_hap}/config/src/signer_config.cpp", + "${signature_tools_hap}/entity/src/content_digest_algorithm.cpp", + "${signature_tools_hap}/entity/src/param_constants.cpp", + "${signature_tools_hap}/entity/src/signature_algorithm_helper.cpp", + "${signature_tools_hap}/provider/src/local_sign_provider.cpp", + "${signature_tools_hap}/provider/src/remote_sign_provider.cpp", + "${signature_tools_hap}/provider/src/sign_provider.cpp", + "${signature_tools_hap}/sign/src/sign_elf.cpp", + "${signature_tools_hap}/utils/src/dynamic_lib_handle.cpp", + "${signature_tools_hap}/sign/src/bc_pkcs7_generator.cpp", +] diff --git a/binary_sign_tool/hap/utils/include/dynamic_lib_handle.h b/binary_sign_tool/hap/utils/include/dynamic_lib_handle.h new file mode 100644 index 00000000..31052a8e --- /dev/null +++ b/binary_sign_tool/hap/utils/include/dynamic_lib_handle.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGNATRUETOOLS_DYNAMIC_LIB_HANDLE_H +#define SIGNATRUETOOLS_DYNAMIC_LIB_HANDLE_H + +#include + +#include "signature_tools_log.h" +#include "params.h" + +namespace OHOS { +namespace SignatureTools { +class DynamicLibHandle { +public: + static void* handle; + DynamicLibHandle() = default; + ~DynamicLibHandle(); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif \ No newline at end of file diff --git a/binary_sign_tool/hap/utils/include/hap_utils.h b/binary_sign_tool/hap/utils/include/hap_utils.h new file mode 100644 index 00000000..e0d0cd9e --- /dev/null +++ b/binary_sign_tool/hap/utils/include/hap_utils.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGNATRUETOOLS_HAP_UTILS_H +#define SIGNATRUETOOLS_HAP_UTILS_H + +#include +#include +#include +#include +#include +#include + +#include "content_digest_algorithm.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { +class HapUtils { +public: + static constexpr int HAP_SIGNATURE_SCHEME_V1_BLOCK_ID = 0x20000000; + static constexpr int HAP_PROOF_OF_ROTATION_BLOCK_ID = 0x20000001; + static constexpr int HAP_PROFILE_BLOCK_ID = 0x20000002; + static constexpr int HAP_PROPERTY_BLOCK_ID = 0x20000003; + static constexpr int HAP_CODE_SIGN_BLOCK_ID = 0x30000001; + static constexpr int CONTENT_DIGESTED_CHUNK_MAX_SIZE_BYTES = 1024 * 1024; + static constexpr int CONTENT_VERSION = 2; + static constexpr int BIT_SIZE = 8; + static constexpr int HALF_BIT_SIZE = 4; + static constexpr int INT_SIZE = 4; + static constexpr int BLOCK_NUMBER = 1; + static constexpr int HAP_SIGN_SCHEME_V2_BLOCK_VERSION = 2; + static constexpr int HAP_SIGN_SCHEME_V3_BLOCK_VERSION = 3; + static constexpr int64_t HAP_SIG_BLOCK_MAGIC_LO_V2 = 0x2067695320504148LL; + static constexpr int64_t HAP_SIG_BLOCK_MAGIC_HI_V2 = 0x3234206b636f6c42LL; + static constexpr int64_t HAP_SIG_BLOCK_MAGIC_LO_V3 = 0x676973207061683cLL; + static constexpr int64_t HAP_SIG_BLOCK_MAGIC_HI_V3 = 0x3e6b636f6c62206eLL; + static constexpr int HAP_SIG_BLOCK_HEADER_SIZE = 32; + static constexpr int HAP_SIG_BLOCK_MIN_SIZE = HAP_SIG_BLOCK_HEADER_SIZE; + static constexpr int BLOCK_SIZE = 8; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif diff --git a/binary_sign_tool/hap/utils/src/dynamic_lib_handle.cpp b/binary_sign_tool/hap/utils/src/dynamic_lib_handle.cpp new file mode 100644 index 00000000..5088eeaf --- /dev/null +++ b/binary_sign_tool/hap/utils/src/dynamic_lib_handle.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "dynamic_lib_handle.h" + +namespace OHOS { +namespace SignatureTools { +void* DynamicLibHandle::handle = nullptr; +DynamicLibHandle::~DynamicLibHandle() +{ + if (handle != nullptr) { + if (dlclose(handle) != 0) { + SIGNATURE_TOOLS_LOGE("dlclose() %s", dlerror()); + } + } +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/hap/verify/include/matching_result.h b/binary_sign_tool/hap/verify/include/matching_result.h new file mode 100644 index 00000000..8bfbc196 --- /dev/null +++ b/binary_sign_tool/hap/verify/include/matching_result.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_MATCHING_RESULT_H +#define SIGNATRUETOOLS_MATCHING_RESULT_H +namespace OHOS { +namespace SignatureTools { +enum SourcesTrusted { + OTHER_TRUSTED_SOURCE = 0, + APP_GALLARY, + APP_SYSTEM, + APP_THIRD_PARTY_PRELOAD, +}; +enum StatesMatching { + DO_NOT_MATCH = 0, + MATCH_WITH_SIGN, + MATCH_WITH_PROFILE, + MATCH_WITH_PROFILE_DEBUG, + MATCH_WITH_TICKET, +}; +struct MatchingResult { + StatesMatching matchState; + SourcesTrusted source; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // HAP_MATCHING_RESULT_H diff --git a/binary_sign_tool/main.cpp b/binary_sign_tool/main.cpp new file mode 100644 index 00000000..edcb75a1 --- /dev/null +++ b/binary_sign_tool/main.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "params_run_tool.h" +using namespace OHOS::SignatureTools; +int main(int argc, char** argv) +{ + // prepare modes vector by macro DEFINE_MODE which subscribe UPDATER_MAIN_PRE_EVENT event + bool isSuccess = ParamsRunTool::ProcessCmd(argv, argc); + if (isSuccess) { + return 0; + } + return 1; +} \ No newline at end of file diff --git a/binary_sign_tool/profile/include/pkcs7_data.h b/binary_sign_tool/profile/include/pkcs7_data.h new file mode 100644 index 00000000..17698f7d --- /dev/null +++ b/binary_sign_tool/profile/include/pkcs7_data.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_PKCS7DATA_H +#define SIGNATRUETOOLS_PKCS7DATA_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "openssl/pem.h" +#include "openssl/ecdsa.h" +#include "openssl/evp.h" +#include "openssl/ec.h" +#include "openssl/asn1t.h" +#include "openssl/pkcs7.h" +#include "signer.h" +#include "verify_cert_openssl_utils.h" + + /* compare cert is equal in std::unordered_set for SortX509Stack */ +template<> +struct std::equal_to { + bool operator() (X509* cert1, X509* cert2) const + { + ASN1_INTEGER* serial1 = X509_get_serialNumber(cert1); + ASN1_INTEGER* serial2 = X509_get_serialNumber(cert2); + bool serialEqual = ASN1_INTEGER_cmp(serial1, serial2) == 0; + bool nameEqual = X509_NAME_cmp(X509_get_subject_name(cert1), X509_get_subject_name(cert2)) == 0; + return serialEqual && nameEqual; + } +}; + +/* all cert is put into one bottle */ +template<> +struct std::hash { + size_t operator()(const X509* cert) const + { + return 0; + } +}; + +namespace OHOS { +namespace SignatureTools { +#define PKCS7_NODETACHED_FLAGS (PKCS7_BINARY | PKCS7_NOVERIFY) +#define PKCS7_DETACHED_FLAGS (PKCS7_BINARY | PKCS7_NOVERIFY | PKCS7_DETACHED) +struct PKCS7Attr { + int nid; + int atrtype; + void* value; +}; + +class PKCS7Data { +public: + PKCS7Data(int flags = PKCS7_NODETACHED_FLAGS); + PKCS7Data(const PKCS7Data& pkcs7) = delete; + const PKCS7Data& operator=(const PKCS7Data& pkcs7) = delete; + ~PKCS7Data(); + /* + * @param content The data to be signed + * @param signer signer + * @param sigAlg Signature algorithm SHA256withECDSA/SHA384withECDSA + * @param ret The returned signature result is pkcs7 + * @param attrs It is only used when you need to add an ownerID, and you don't need to process it by default + * @return 0 :success <0 :error + */ + int Sign(const std::string& content, const std::shared_ptr& signer, const std::string& sigAlg, + std::string& ret, std::vector attrs = std::vector()); + /* d2i deserialize */ + int Parse(const std::string& p7bBytes); + int Parse(const std::vector& p7bBytes); + /* When verifying the signature, you don't need to enter content by default, if the data is separated + * (content is not in pkcs7, you need to pass in the original data for verification) + */ + int Verify(const std::string& content = "")const; + /* get original raw content */ + int GetContent(std::string& content) const; + + /* In C++, the certificate chain order is forward, and Java is reversed, + which is historically the result of correcting the certificate chain order */ + static int SortX509Stack(STACK_OF(X509)* certs); + /* Subject information for printing the certificate chain */ + static void PrintCertChainSub(const STACK_OF(X509)* certs); + static std::string GetASN1Time(const ASN1_TIME* tm); + /* Compare the two, first certificate issuers with the second certificate subject info */ + static bool X509NameCompare(const X509* cert, const X509* issuerCert); + /* check pkcs7 sign time in certchain valid period */ + static int CheckSignTimeInValidPeriod(const ASN1_TYPE* signTime, + const ASN1_TIME* notBefore, const ASN1_TIME* notAfter); + +private: + int Parse(const unsigned char** in, long len); + int InitPkcs7(const std::string& content, const std::shared_ptr& signer, + const std::string& sigAlg, std::vector attrs); + /* Verify Signature Value The certificate chain is not verified here */ + int VerifySign(const std::string& content)const; + int VerifyCertChain()const; + /* Verify the validity of the time */ + int CheckSginerInfoSignTimeInCertChainValidPeriod(PKCS7_SIGNER_INFO* signerInfo, STACK_OF(X509)* certs)const; + /* @param cert Entity Certificate + * @param certs Certificate chain (without Entity certificates) + * @param certChain Certificate chain (with Entity certificates) + * @retrun 0 success <0 error + */ + int VerifySignerInfoCertchain(PKCS7* p7, + PKCS7_SIGNER_INFO* signerInfo, + STACK_OF(X509)* certs, + STACK_OF(X509)* certChain)const; + +private: + /* For ease of reading, the following interface will be as consistent as possible with the OpenSSL + library interface style, and the return value is 1 success and 0 failure */ + int Pkcs7SignAttr(PKCS7_SIGNER_INFO* si); + + int Pkcs7AddTimeDigestAndSignAttr(PKCS7_SIGNER_INFO* si, EVP_MD_CTX* mctx); + + int Pkcs7DataFinalSignAttr(STACK_OF(PKCS7_SIGNER_INFO)* si_sk, BIO* bio); + + int Pkcs7DataFinal(PKCS7* p7, BIO* bio); + + int Pkcs7Final(PKCS7* p7, const std::string& content, int flags); + + PKCS7* Pkcs7Sign(X509* signcert, STACK_OF(X509)* certs, const EVP_MD* md, + const std::string& content, int flags, const std::vector& attrs); + +private: + PKCS7* m_p7 = NULL; + int m_flags; + std::shared_ptr m_signer; // tmp + std::string m_sigAlg; // tmp +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_PKCS7DATA_H \ No newline at end of file diff --git a/binary_sign_tool/profile/include/profile_info.h b/binary_sign_tool/profile/include/profile_info.h new file mode 100644 index 00000000..4e5a2c66 --- /dev/null +++ b/binary_sign_tool/profile/include/profile_info.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_PROFILE_INFO_H +#define SIGNATRUETOOLS_PROFILE_INFO_H + +#include +#include +#include + +#include "export_define.h" + +namespace OHOS { +namespace SignatureTools { + +enum ProvisionType { + NONE_PROVISION_TYPE, + RELEASE, + DEBUG +}; +enum AppDistType { + NONE_TYPE, + APP_GALLERY, + ENTERPRISE, + OS_INTEGRATION, + CROWDTESTING, + ENTERPRISE_NORMAL, + ENTERPRISE_MDM +}; +typedef struct BundleInfoSt { + std::string developerId; + std::string apl; + std::string distributionCertificate; + std::string developmentCertificate; + std::string bundleName; + std::string appIdentifier; + std::vector dataGroupIds; + std::string appFeature; +}BundleInfo; +typedef struct AclsSt { + std::vector allowedAcls; +}Acls; +typedef struct PermissionsSt { + std::vector restrictedCapabilities; + std::vector restrictedPermissions; +}Permissions; +typedef struct DebugInfoSt { + std::vector deviceIds; + std::string deviceIdType; +}DebugInfo; +typedef struct ValiditySt { + int64_t notAfter = 0; + int64_t notBefore = 0; +}Validity; +typedef struct MetadataSt { + std::string value; + std::string resource; + std::string name; +}Metadata; +struct ProfileInfo { + DLL_EXPORT ProfileInfo(); + DLL_EXPORT ~ProfileInfo(); + DLL_EXPORT ProfileInfo(const ProfileInfo& info); + DLL_EXPORT ProfileInfo& operator=(const ProfileInfo& info); + int32_t versionCode = 0; + std::string uuid; + std::string versionName; + AppDistType distributionType = NONE_TYPE; + ProvisionType type = NONE_PROVISION_TYPE; + BundleInfoSt bundleInfo; + PermissionsSt permissions; + AclsSt acls; + std::string issuer; + DebugInfoSt debugInfo; + std::string fingerprint; + std::string appId; + std::vector appPrivilegeCapabilities; + ValiditySt validity; + int32_t profileBlockLength = 0; + std::vector metadatas; + std::string organization; + std::string appServiceCapabilities; + std::unique_ptr profileBlock; +}; +} // namespace SignatureTools +} // namespace OHOS + +#endif // SIGNATRUETOOLS_PROFILE_INFO_H diff --git a/binary_sign_tool/profile/include/profile_sign_tool.h b/binary_sign_tool/profile/include/profile_sign_tool.h new file mode 100644 index 00000000..f6bac4ad --- /dev/null +++ b/binary_sign_tool/profile/include/profile_sign_tool.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_PROFILESIGNTOOOL_H +#define SIGNATRUETOOLS_PROFILESIGNTOOOL_H + +#include +#include + +#include "openssl/pkcs7.h" +#include "openssl/err.h" +#include "openssl/x509.h" +#include "signer.h" +#include "localization_adapter.h" +#include "pkcs7_data.h" + +namespace OHOS { +namespace SignatureTools { +/** + * To sign and verify profile. + * + * @since 2021/12/28 + */ +class ProfileSignTool { +public: + /** + * generateP7b. + * + * @param adapter local adapter with params + * @param content content to sign + * @param ret signed content + * @return 0:success <0:error + */ + static int GenerateP7b(LocalizationAdapter& adapter, const std::string& content, std::string& ret); + /** + * signProfile. + * + * @param content content to sign + * @param signer signer + * @param sigAlg sign algorithm only SHAwith256 or SHAwith384 + * @ret signed data + * @return 0:success <0:error + */ + static int SignProfile(const std::string& content, + const std::shared_ptr& signer, const std::string& sigAlg, std::string& ret); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_PROFILESIGNTOOOL_H \ No newline at end of file diff --git a/binary_sign_tool/profile/include/profile_verify.h b/binary_sign_tool/profile/include/profile_verify.h new file mode 100644 index 00000000..1d5bad28 --- /dev/null +++ b/binary_sign_tool/profile/include/profile_verify.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_PROFILE_VERIFY_H +#define SIGNATRUETOOLS_PROFILE_VERIFY_H + +#include "export_define.h" +#include "profile_info.h" + +namespace OHOS { +namespace SignatureTools { + +#define DEV_UUID_LEN 65 +enum AppProvisionVerifyResult { + PROVISION_INVALID, // Invalid json string + PROVISION_OK, // Passed + PROVISION_UNSUPPORTED_DEVICE_TYPE, // Failed to get device id + PROVISION_NUM_DEVICE_EXCEEDED, // No. of device exceeds maximum number + PROVISION_DEVICE_UNAUTHORIZED, // Device id not included +}; +/** +* @brief Parse and verify the app provision +* @param appProvision The app provision json string. +* @param info Out param, the parsed app provision structure. +* @return AppProvisionVerifyResult Verification result. +*/ +DLL_EXPORT AppProvisionVerifyResult ParseAndVerify(const std::string& appProvision, ProfileInfo& info); +/** +* @brief Parse app provision +* @param appProvision The app provision json string. +* @param info Out param, the parsed app provision structure. +* @return AppProvisionVerifyResult parse result. +*/ +DLL_EXPORT AppProvisionVerifyResult ParseProvision(const std::string& appProvision, ProfileInfo& info); +/** +* @brief Parse app provision profile +* @param appProvision The app provision json string. +* @param info Out param, the parsed app provision structure. +* @return AppProvisionVerifyResult parse result. +*/ +DLL_EXPORT AppProvisionVerifyResult ParseProfile(const std::string& appProvision, ProfileInfo& info); +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_PROFILE_VERIFY_H diff --git a/binary_sign_tool/profile/signature_tools_profile.gni b/binary_sign_tool/profile/signature_tools_profile.gni new file mode 100644 index 00000000..f2728986 --- /dev/null +++ b/binary_sign_tool/profile/signature_tools_profile.gni @@ -0,0 +1,22 @@ +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("../signature_tools.gni") +signature_tools_profile_include = [ "${signature_tools_profile}/include" ] + +signature_tools_profile_src = [ + "${signature_tools_profile}/src/profile_info.cpp", + "${signature_tools_profile}/src/profile_verify.cpp", + "${signature_tools_profile}/src/pkcs7_data.cpp", + "${signature_tools_profile}/src/profile_sign_tool.cpp", +] diff --git a/binary_sign_tool/profile/src/pkcs7_data.cpp b/binary_sign_tool/profile/src/pkcs7_data.cpp new file mode 100644 index 00000000..0715ec03 --- /dev/null +++ b/binary_sign_tool/profile/src/pkcs7_data.cpp @@ -0,0 +1,821 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "signature_tools_log.h" +#include "signature_tools_errno.h" +#include "verify_hap_openssl_utils.h" +#include "signer.h" +#include "securec.h" +#include "constant.h" +#include "pkcs7_data.h" + +namespace OHOS { +namespace SignatureTools { + +static constexpr int BUFFER_SIZE = 4096; + +static int PKCS7AddAttribute(PKCS7* p7, const std::vector& attrs) +{ + STACK_OF(PKCS7_SIGNER_INFO)* signerInfos = PKCS7_get_signer_info(p7); + if (signerInfos == NULL || sk_PKCS7_SIGNER_INFO_num(signerInfos) != 1) { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, + "signer info count not equal 1,pkcs7 add customize attribute failed"); + return INVALIDPARAM_ERROR; + } + PKCS7_SIGNER_INFO* signerInfo = sk_PKCS7_SIGNER_INFO_value(signerInfos, 0); + for (PKCS7Attr attr : attrs) { + if (PKCS7_add_signed_attribute(signerInfo, attr.nid, attr.atrtype, attr.value) != 1) { + if (attr.atrtype == V_ASN1_UTF8STRING) + ASN1_STRING_free(reinterpret_cast(attr.value)); + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, + "pkcs7 add customize attribute failed"); + return RET_FAILED; + } + } + return RET_OK; +} + +static int I2dPkcs7Str(PKCS7* p7, std::string& ret) +{ + /* raw data exported in pkcs7 */ + unsigned char* out = NULL; + int outSize = 0; + /* Deserialize to obtain the p7b byte stream */ + outSize = i2d_PKCS7(p7, &out); + if (out == NULL || outSize <= 0) { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, + "pkcs7 is invalid"); + return INVALIDPARAM_ERROR; + } + ret.clear(); + ret.resize(outSize); + std::copy(out, out + outSize, &ret[0]); + OPENSSL_free(out); + return RET_OK; +} + +static int SetSignerInfoSignAlgor(PKCS7_SIGNER_INFO* info) +{ + int signNid = 0; + int hashNid = 0; + X509_ALGOR* dig; + X509_ALGOR* sig; + PKCS7_SIGNER_INFO_get0_algs(info, NULL, &dig, &sig); + if (dig == NULL || dig->algorithm == NULL || + (hashNid = OBJ_obj2nid(dig->algorithm)) == NID_undef || + !OBJ_find_sigid_by_algs(&signNid, hashNid, NID_X9_62_id_ecPublicKey) || + X509_ALGOR_set0(sig, OBJ_nid2obj(signNid), V_ASN1_UNDEF, 0) != 1) { + return 0; + } + return 1; +} + +static int VerifySignature(PKCS7* pkcs7, BIO* p7bio) +{ + /* signature information */ + STACK_OF(PKCS7_SIGNER_INFO)* skSignerInfo = NULL; + /* signature count */ + int signerCount = 0; + /* verify signature value */ + skSignerInfo = PKCS7_get_signer_info(pkcs7); + signerCount = sk_PKCS7_SIGNER_INFO_num(skSignerInfo); + for (int i = 0; i < signerCount; i++) { + PKCS7_SIGNER_INFO* signerInfo = sk_PKCS7_SIGNER_INFO_value(skSignerInfo, i); + X509* sigCert = PKCS7_cert_from_signer_info(pkcs7, signerInfo); + if (PKCS7_signatureVerify(p7bio, pkcs7, signerInfo, sigCert) != 1) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "signature value verify failed"); + return VERIFY_ERROR; + } + } + return RET_OK; +} + +PKCS7Data::PKCS7Data(int flags) : m_p7(nullptr), m_flags(flags) +{ +} + +PKCS7Data::~PKCS7Data() +{ + PKCS7_free(m_p7); + m_p7 = NULL; +} + +int PKCS7Data::Sign(const std::string& content, const std::shared_ptr& signer, + const std::string& sigAlg, std::string& ret, std::vector attrs) +{ + int result = RET_OK; + if ((result = InitPkcs7(content, signer, sigAlg, attrs)) < 0) { + goto err; + } + + /* serialization */ + if ((result = I2dPkcs7Str(m_p7, ret)) < 0) { + goto err; + } + /* release resources */ +err: + if (result < 0) { + SIGNATURE_TOOLS_LOGE("sign failed"); + } + return result; +} + +int PKCS7Data::Parse(const std::string& p7bBytes) +{ + const unsigned char* data = reinterpret_cast(&p7bBytes[0]); + return Parse(&data, static_cast(p7bBytes.size())); +} +int PKCS7Data::Parse(const std::vector& p7bBytes) +{ + const unsigned char* data = reinterpret_cast(&p7bBytes[0]); + return Parse(&data, static_cast(p7bBytes.size())); +} +int PKCS7Data::Parse(const unsigned char** in, long len) +{ + /* If p7 has been initialized, it will be released */ + if (m_p7) { + PKCS7_free(m_p7); + m_p7 = NULL; + } + /* Deserialize */ + m_p7 = d2i_PKCS7(NULL, in, len); + if (m_p7 == NULL) { + PrintErrorNumberMsg("PARSE_ERROR", PARSE_ERROR, "invalid p7b data, parse failed"); + return PARSE_ERROR; + } + return RET_OK; +} + +int PKCS7Data::Verify(const std::string& content) const +{ + if (VerifySign(content) < 0) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "signature verify failed"); + return VERIFY_ERROR; + } + if (VerifyCertChain() < 0) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "cert Chain verify failed"); + PrintCertChainSub(m_p7->d.sign->cert); + return VERIFY_ERROR; + } + return RET_OK; +} + +int PKCS7Data::GetContent(std::string& originalRawData) const +{ + BIO* oriBio = PKCS7_dataDecode(m_p7, NULL, NULL, NULL); + if (oriBio == NULL) { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, "pkcs7 get content data failed!"); + return INVALIDPARAM_ERROR; + } + char buf[BUFFER_SIZE]{0}; + size_t readBytes = 0; + while (BIO_read_ex(oriBio, buf, sizeof(buf), &readBytes) == 1) { + originalRawData.append(buf, readBytes); + } + BIO_free_all(oriBio); + return RET_OK; +} + +static void PKCS7AddCrls(PKCS7* p7, STACK_OF(X509_CRL)* crls) +{ + for (int i = 0; i < sk_X509_CRL_num(crls); i++) { + PKCS7_add_crl(p7, sk_X509_CRL_value(crls, i)); + } +} + +int PKCS7Data::InitPkcs7(const std::string& content, const std::shared_ptr& signer, + const std::string& sigAlg, std::vector attrs) +{ + STACK_OF(X509)* certs = NULL; + /* hash algorithm */ + const EVP_MD* md = NULL; + /* entity certificate */ + X509* cert = NULL; + int result = RET_OK; + if (signer == NULL) { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, "signer is NULL , sign failed"); + result = INVALIDPARAM_ERROR; + goto err; + } + m_signer = signer; + m_sigAlg = sigAlg; + certs = signer->GetCertificates(); + if (SortX509Stack(certs) < 0) { + result = RET_FAILED; + goto err; + } + if (sigAlg == SIGN_ALG_SHA384) { + md = EVP_sha384(); + } else if (sigAlg == SIGN_ALG_SHA256) { + md = EVP_sha256(); + } else { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, + sigAlg + "is invalid sigAlg, please use SHA256withECDSA/SHA384withECDSA, sign failed"); + result = INVALIDPARAM_ERROR; + goto err; + } + /* Extract the entity certificate from the certificate chain */ + cert = sk_X509_delete(certs, 0); + m_p7 = Pkcs7Sign(cert, certs, md, content, m_flags, attrs); + if (m_p7 == NULL) { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", SIGN_ERROR, "p7 is NULL, pkcs7 sign failed"); + result = SIGN_ERROR; + goto err; + } + PKCS7AddCrls(m_p7, signer->GetCrls()); + +err: + sk_X509_pop_free(certs, X509_free); + X509_free(cert); + return result; +} + +void PKCS7Data::PrintCertChainSub(const STACK_OF(X509)* certs) +{ + if (certs == NULL) + return; + SIGNATURE_TOOLS_LOGI("certChainSubject:"); + int certNum = sk_X509_num(certs); + SIGNATURE_TOOLS_LOGI("certNum%s", std::to_string(certNum).c_str()); + for (int i = 0; i < certNum; i++) { + SIGNATURE_TOOLS_LOGI("certificate %s", std::to_string(i).c_str()); + std::string sub; + VerifyCertOpensslUtils::GetSubjectFromX509(sk_X509_value(certs, i), sub); + SIGNATURE_TOOLS_LOGI("%s", sub.c_str()); + } +} + +std::string PKCS7Data::GetASN1Time(const ASN1_TIME* tm) +{ + if (tm == NULL) { + return ""; + } + /* Convert the ASN1_TIME structure to a standard tm structure. */ + struct tm time; + ASN1_TIME_to_tm(tm, &time); + /* Convert to local time(considering the time zone) */ + time_t t = mktime(&time); + if (t < 0) { + return ""; + } + struct tm* localTime = localtime(&t); + if (localTime == nullptr) { + return ""; + } + /* Print local time */ + char buf[128] = {0}; + if (sprintf_s(buf, sizeof(buf), "%04d-%02d-%02d %02d:%02d:%02d", + localTime->tm_year + YEAR1900, localTime->tm_mon + 1, localTime->tm_mday, + localTime->tm_hour, localTime->tm_min, localTime->tm_sec) == -1) { + return ""; + } + return std::string(buf, strlen(buf)); +} + +bool PKCS7Data::X509NameCompare(const X509* cert, const X509* issuerCert) +{ + if (cert == nullptr || issuerCert == nullptr) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, + "input cert is NULL"); + return false; + } + X509_NAME* aName = X509_get_issuer_name(cert); + X509_NAME* bName = X509_get_subject_name(issuerCert); + if (X509_NAME_cmp(aName, bName) != 0) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, + "cert issuer name is not equal to its issuer\'s name"); + return false; + } + return true; +} + +int PKCS7Data::CheckSignTimeInValidPeriod(const ASN1_TYPE* signTime, + const ASN1_TIME* notBefore, const ASN1_TIME* notAfter) +{ + if (notBefore == nullptr || notBefore->data == nullptr || notAfter == nullptr || notAfter->data == nullptr) { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, + "invalid period, check signtime failed please use valid period to to check signtime"); + return INVALIDPARAM_ERROR; + } + if (signTime == nullptr || signTime->value.asn1_string == nullptr || + signTime->value.asn1_string->data == nullptr) { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, "signtime is NULL"); + return INVALIDPARAM_ERROR; + } + ASN1_TIME* tm = ASN1_TIME_new(); + ASN1_TIME_set_string(tm, (reinterpret_cast(signTime->value.asn1_string->data))); + if (ASN1_TIME_compare(notBefore, signTime->value.asn1_string) > 0 || + ASN1_TIME_compare(notAfter, signTime->value.asn1_string) < 0) { + SIGNATURE_TOOLS_LOGE("sign time invalid, signTime: %s, notBefore: %s, " + "notAfter: %s", GetASN1Time(tm).c_str(), + GetASN1Time(notBefore).c_str(), GetASN1Time(notAfter).c_str()); + ASN1_TIME_free(tm); + return RET_FAILED; + } + ASN1_TIME_free(tm); + return RET_OK; +} + +static X509* FindSubCertThenEraseItFromSets(X509* cert, std::unordered_set& x509Sets) +{ + X509* ret = NULL; + for (X509* c : x509Sets) { + X509_NAME* name1 = X509_get_subject_name(cert); + X509_NAME* name2 = X509_get_issuer_name(c); + if (X509_NAME_cmp(name1, name2) == 0) { + x509Sets.erase(c); + ret = c; + break; + } + } + return ret; +} + +int PKCS7Data::SortX509Stack(STACK_OF(X509)* certs) +{ + std::unordered_set x509Sets; + std::listcertChain; + X509* tmp = NULL; + int result = RET_FAILED; + + if (sk_X509_num(certs) < MIN_CERTS_NUM) { + PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, "cert of certchain count less than two!"); + goto err; + } + for (int i = 0; i < sk_X509_num(certs); i++) { + x509Sets.insert(sk_X509_value(certs, i)); + } + if (sk_X509_num(certs) != static_cast(x509Sets.size())) { + PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, "sort x509 certchain failed!"); + goto err; + } + for (X509* cert : x509Sets) { + if (X509_name_cmp(X509_get_subject_name(cert), X509_get_issuer_name(cert)) == 0) { + tmp = cert; + x509Sets.erase(cert); + break; + } + } + if (tmp == NULL) { + PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, + "can't find root cert from certchain ,sort x509 certchain failed!"); + goto err; + } + certChain.push_front(tmp); + while ((tmp = FindSubCertThenEraseItFromSets(tmp, x509Sets))) { + certChain.push_front(tmp); + } + if (x509Sets.size() != 0) { + PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, + "certchain contain invalid cert, sort x509 certchain failed!"); + goto err; + } + while (sk_X509_num(certs)) { + sk_X509_pop(certs); + } + for (X509* cert : certChain) { + sk_X509_push(certs, cert); + } + result = RET_OK; +err: + return result; +} + +int PKCS7Data::VerifySign(const std::string& content)const +{ + BIO* inBio = NULL; + if ((m_flags & PKCS7_DETACHED)) { + inBio = BIO_new_mem_buf(reinterpret_cast(content.c_str()), + static_cast(content.size())); + if (inBio == NULL) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, + "new mem buf error!,pkcs7 verify signature failed"); + return VERIFY_ERROR; + } + } + if (PKCS7_verify(m_p7, NULL, NULL, inBio, NULL, m_flags) != 1) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "pkcs7 verify signature failed"); + BIO_free(inBio); + return VERIFY_ERROR; + } + BIO_free(inBio); + return RET_OK; +} + +int PKCS7Data::VerifyCertChain()const +{ + /* Validate the certificate chain */ + STACK_OF(PKCS7_SIGNER_INFO)* skSignerInfo = PKCS7_get_signer_info(m_p7); + int signerCount = sk_PKCS7_SIGNER_INFO_num(skSignerInfo); + int c = signerCount; + STACK_OF(X509)* certs = NULL; + int result = RET_FAILED; + /* Original certificate chain */ + STACK_OF(X509)* certChain = m_p7->d.sign->cert; + /* Copy of the certificate chain, with the entity certificate removed later */ + certs = sk_X509_dup(certChain); + if (SortX509Stack(certs) < 0) { + SIGNATURE_TOOLS_LOGE("sort x509 stack failed, verify certchain failed"); + goto err; + } + /* Retrieve the certificate chain without the entity certificate */ + while (c--) { + sk_X509_delete(certs, 0); + } + for (int i = 0; i < signerCount; i++) { + PKCS7_SIGNER_INFO* signerInfo = sk_PKCS7_SIGNER_INFO_value(skSignerInfo, i); + if ((result = VerifySignerInfoCertchain(m_p7, signerInfo, certs, certChain)) < 0) { + SIGNATURE_TOOLS_LOGE("verify certchain failed"); + goto err; + } + } + result = RET_OK; +err: + sk_X509_free(certs); + return result; +} + +int PKCS7Data::CheckSginerInfoSignTimeInCertChainValidPeriod(PKCS7_SIGNER_INFO* signerInfo, + STACK_OF(X509)* certs) const +{ + if (signerInfo == NULL || certs == NULL) { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, "input is NULL, check signtime invalid"); + return INVALIDPARAM_ERROR; + } + ASN1_TYPE* signTime = PKCS7_get_signed_attribute(signerInfo, NID_pkcs9_signingTime); + for (int i = 0; i < sk_X509_num(certs); i++) { + X509* cert = sk_X509_value(certs, i); + const ASN1_TIME* notBefore = X509_get0_notBefore(cert); + const ASN1_TIME* notAfter = X509_get0_notAfter(cert); + if (CheckSignTimeInValidPeriod(signTime, notBefore, notAfter) < 0) { + SIGNATURE_TOOLS_LOGE("pkcs7 sign time check failed"); + return INVALIDPARAM_ERROR; + } + } + return RET_OK; +} + +int PKCS7Data::VerifySignerInfoCertchain(PKCS7* pkcs7, PKCS7_SIGNER_INFO* signerInfo, + STACK_OF(X509)* certs, STACK_OF(X509)* certChain)const +{ + X509* sigCert = PKCS7_cert_from_signer_info(pkcs7, signerInfo); + int j = 0; + /* Trace back through the subject information and validate the signature value of each certificate */ + if (!X509NameCompare(sigCert, sk_X509_value(certs, 0))) { + SIGNATURE_TOOLS_LOGE("entity name compare not equal, verify failed"); + return VERIFY_ERROR; + } + /* verify entity certificate signature value */ + if (!VerifyCertOpensslUtils::CertVerify(sigCert, sk_X509_value(certs, 0))) { + SIGNATURE_TOOLS_LOGE("entity cert signature verify failed"); + return VERIFY_ERROR; + } + for (; j + 1 < sk_X509_num(certs); j++) { + if (!X509NameCompare(sk_X509_value(certs, j), sk_X509_value(certs, j + 1))) { + SIGNATURE_TOOLS_LOGE("sub cert name compare not equal, verify failed"); + return VERIFY_ERROR; + } + /* Verify the signature value of the intermediate certificate */ + if (!VerifyCertOpensslUtils::CertVerify(sk_X509_value(certs, j), sk_X509_value(certs, j + 1))) { + SIGNATURE_TOOLS_LOGE("sub cert signature verify failed"); + return VERIFY_ERROR; + } + } + if (!X509NameCompare(sk_X509_value(certs, j), sk_X509_value(certs, j))) { + SIGNATURE_TOOLS_LOGE("root cert name compare not equal, verify failed"); + return VERIFY_ERROR; + } + /* Verify the signature value of the root certificate */ + if (!VerifyCertOpensslUtils::CertVerify(sk_X509_value(certs, j), sk_X509_value(certs, j))) { + SIGNATURE_TOOLS_LOGE("root cert signature verify failed"); + return VERIFY_ERROR; + } + /* Verify that the signature time in the signature information is within the validity period of + the certificate chain (entity certificate will be verified in PKCS7_verify) */ + if (CheckSginerInfoSignTimeInCertChainValidPeriod(signerInfo, certChain) < 0) { + SIGNATURE_TOOLS_LOGE("sign time is invalid,verify failed"); + return VERIFY_ERROR; + } + return RET_OK; +} + +int PKCS7Data::Pkcs7SignAttr(PKCS7_SIGNER_INFO* info) +{ + unsigned char* attrBuf = NULL; + int attrLen; + + std::string data; + std::string signature; + unsigned char* sigRet = NULL; + int sigLen = 0; + + attrLen = ASN1_item_i2d(reinterpret_cast(info->auth_attr), &attrBuf, + ASN1_ITEM_rptr(PKCS7_ATTR_SIGN)); + if (!attrBuf) { + OPENSSL_free(attrBuf); + return 0; + } + + data.assign(reinterpret_cast(attrBuf), attrLen); + signature = m_signer->GetSignature(data, m_sigAlg); + if (signature.empty()) { + OPENSSL_free(attrBuf); + return 0; + } + sigLen = signature.size(); + sigRet = reinterpret_cast(OPENSSL_malloc(sigLen)); + if (sigRet == NULL) { + OPENSSL_free(attrBuf); + return 0; + } + std::copy(&signature[0], &signature[0] + signature.size(), sigRet); + ASN1_STRING_set0(info->enc_digest, sigRet, sigLen); + OPENSSL_free(attrBuf); + return 1; +} + +static ASN1_OCTET_STRING* PKCS7GetASN1Content(PKCS7* pkcs7) +{ + if (PKCS7_type_is_data(pkcs7)) { + return pkcs7->d.data; + } + return NULL; +} + +int PKCS7Data::Pkcs7AddTimeDigestAndSignAttr(PKCS7_SIGNER_INFO* info, EVP_MD_CTX* hashCtx) +{ + unsigned char hashData[EVP_MAX_MD_SIZE]; + unsigned int hashLen; + + /* add signing time */ + if (!PKCS7_get_signed_attribute(info, NID_pkcs9_signingTime)) { + if (!PKCS7_add0_attrib_signing_time(info, NULL)) { + return 0; + } + } + + /* add digest */ + if (!EVP_DigestFinal_ex(hashCtx, hashData, &hashLen)) { + return 0; + } + if (!PKCS7_add1_attrib_digest(info, hashData, hashLen)) { + return 0; + } + + /* sign the attributes */ + if (!Pkcs7SignAttr(info)) { + return 0; + } + + return 1; +} + +static BIO* PKCS7SearchDigest(EVP_MD_CTX** pHash, BIO* io, int numberID) +{ + while ((io = BIO_find_type(io, BIO_TYPE_MD))) { + BIO_get_md_ctx(io, pHash); + if (*pHash == NULL) { + return NULL; + } + if (EVP_MD_CTX_type(*pHash) == numberID) { + return io; + } + io = BIO_next(io); + } + return NULL; +} + +static int PKCS7DataFinalCheck(PKCS7* pkcs7, BIO* bio, + STACK_OF(PKCS7_SIGNER_INFO)** psk, ASN1_OCTET_STRING** pos) +{ + int id = 0; + + if (pkcs7 == NULL || pkcs7->d.ptr == NULL) { + return 0; + } + + id = OBJ_obj2nid(pkcs7->type); + pkcs7->state = PKCS7_S_HEADER; + + if (id == NID_pkcs7_signed) { + *psk = pkcs7->d.sign->signer_info; + *pos = PKCS7GetASN1Content(pkcs7->d.sign->contents); + if (PKCS7_type_is_data(pkcs7->d.sign->contents) && pkcs7->detached) { + ASN1_OCTET_STRING_free(*pos); + *pos = NULL; + pkcs7->d.sign->contents->d.data = NULL; + } + return 1; + } + return 0; +} + +int PKCS7Data::Pkcs7DataFinalSignAttr(STACK_OF(PKCS7_SIGNER_INFO)* infoStack, BIO* bio) +{ + EVP_MD_CTX* hashCtx = NULL; + STACK_OF(X509_ATTRIBUTE)* attrStack = NULL; + BIO* ioTmp = NULL; + int result = 0; + EVP_MD_CTX* ctxTmp = EVP_MD_CTX_new(); + if (ctxTmp == NULL) { + return 0; + } + + if (infoStack == NULL) { + goto err; + } + for (int i = 0; i < sk_PKCS7_SIGNER_INFO_num(infoStack); i++) { + PKCS7_SIGNER_INFO* info = sk_PKCS7_SIGNER_INFO_value(infoStack, i); + + int numberID = OBJ_obj2nid(info->digest_alg->algorithm); + + ioTmp = bio; + + ioTmp = PKCS7SearchDigest(&hashCtx, ioTmp, numberID); + + if (ioTmp == NULL || !EVP_MD_CTX_copy_ex(ctxTmp, hashCtx)) { + goto err; + } + + attrStack = info->auth_attr; + + if (sk_X509_ATTRIBUTE_num(attrStack) > 0) { + if (!Pkcs7AddTimeDigestAndSignAttr(info, ctxTmp)) { + goto err; + } + } else { + goto err; + } + } + result = 1; +err: + EVP_MD_CTX_free(ctxTmp); + return result; +} + +static int PKCS7DataFinalSetContent(PKCS7* pkcs7, ASN1_OCTET_STRING* asn1Str, BIO* io) +{ + BIO* ioTmp = NULL; + if (!PKCS7_is_detached(pkcs7)) { + if (asn1Str == NULL) { + return 0; + } + if (!(asn1Str->flags & ASN1_STRING_FLAG_NDEF)) { + char* contentData; + long contentLen; + ioTmp = BIO_find_type(io, BIO_TYPE_MEM); + if (ioTmp == NULL) { + return 0; + } + contentLen = BIO_get_mem_data(ioTmp, &contentData); + + BIO_set_flags(ioTmp, BIO_FLAGS_MEM_RDONLY); + BIO_set_mem_eof_return(ioTmp, 0); + ASN1_STRING_set0(asn1Str, reinterpret_cast(contentData), contentLen); + } + } + return 1; +} +int PKCS7Data::Pkcs7DataFinal(PKCS7* pkcs7, BIO* io) +{ + STACK_OF(PKCS7_SIGNER_INFO)* infoStack = NULL; + ASN1_OCTET_STRING* os = NULL; + + if (!PKCS7DataFinalCheck(pkcs7, io, &infoStack, &os) || + !Pkcs7DataFinalSignAttr(infoStack, io) || + !PKCS7DataFinalSetContent(pkcs7, os, io)) { + return 0; + } + return 1; +} + +int PKCS7Data::Pkcs7Final(PKCS7* pkcs7, const std::string& content, int flags) +{ + BIO* p7bio; + int result = 0; + + if ((p7bio = PKCS7_dataInit(pkcs7, NULL)) == NULL) { + return 0; + } + + if (BIO_write(p7bio, content.c_str(), static_cast(content.size())) <= 0) { + SIGNATURE_TOOLS_LOGE("add json data to pkcs7 failed"); + goto err; + } + + (void)BIO_flush(p7bio); + + if (!Pkcs7DataFinal(pkcs7, p7bio)) { + goto err; + } + /* Verify the signature value */ + if (VerifySignature(pkcs7, p7bio) < 0) { + goto err; + } + result = 1; + +err: + BIO_free_all(p7bio); + return result; +} + +static int Pkcs7SetSignerInfo(PKCS7_SIGNER_INFO* info, X509* cert, const EVP_MD* hash) +{ + if (!ASN1_INTEGER_set(info->version, 1) || + !X509_NAME_set(&info->issuer_and_serial->issuer, X509_get_issuer_name(cert))) { + return 0; + } + + ASN1_INTEGER_free(info->issuer_and_serial->serial); + if (!(info->issuer_and_serial->serial = + ASN1_INTEGER_dup(X509_get_serialNumber(cert)))) { + return 0; + } + + X509_ALGOR_set0(info->digest_alg, OBJ_nid2obj(EVP_MD_type(hash)), + V_ASN1_NULL, NULL); + + if (!SetSignerInfoSignAlgor(info)) { + return 0; + } + return 1; +} + +static PKCS7_SIGNER_INFO* Pkcs7AddSignature(PKCS7* pkcs7, X509* cert, const EVP_MD* hash) +{ + PKCS7_SIGNER_INFO* info = NULL; + + if (!(info = PKCS7_SIGNER_INFO_new()) || + !Pkcs7SetSignerInfo(info, cert, hash) || + !PKCS7_add_signer(pkcs7, info)) { + goto err; + } + return info; +err: + PKCS7_SIGNER_INFO_free(info); + return NULL; +} + + +static PKCS7_SIGNER_INFO* Pkcs7AddSignerInfo(PKCS7* pkcs7, X509* entityCert, const EVP_MD* hash, int flags) +{ + PKCS7_SIGNER_INFO* info = NULL; + if ((info = Pkcs7AddSignature(pkcs7, entityCert, hash)) == NULL) { + return NULL; + } + if (!PKCS7_add_certificate(pkcs7, entityCert)) { + return NULL; + } + if (!PKCS7_add_attrib_content_type(info, NULL)) { + return NULL; + } + return info; +} + +PKCS7* PKCS7Data::Pkcs7Sign(X509* entityCert, STACK_OF(X509)* certs, const EVP_MD* hash, + const std::string& content, int flags, const std::vector& attrs) +{ + PKCS7* pkcs7; + + if (!(pkcs7 = PKCS7_new()) || + !PKCS7_set_type(pkcs7, NID_pkcs7_signed) || + !PKCS7_content_new(pkcs7, NID_pkcs7_data) || + !Pkcs7AddSignerInfo(pkcs7, entityCert, hash, flags) || + (PKCS7AddAttribute(pkcs7, attrs) < 0)) { + PKCS7_free(pkcs7); + return NULL; + } + + if (!(flags & PKCS7_NOCERTS)) { + for (int i = 0; i < sk_X509_num(certs); i++) { + if (!PKCS7_add_certificate(pkcs7, sk_X509_value(certs, i))) { + PKCS7_free(pkcs7); + return NULL; + } + } + } + + if (flags & PKCS7_DETACHED) { + PKCS7_set_detached(pkcs7, 1); + } + + if (Pkcs7Final(pkcs7, content, flags)) { + return pkcs7; + } + PKCS7_free(pkcs7); + return NULL; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/profile/src/profile_info.cpp b/binary_sign_tool/profile/src/profile_info.cpp new file mode 100644 index 00000000..8188d62b --- /dev/null +++ b/binary_sign_tool/profile/src/profile_info.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "profile_info.h" +#include "securec.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { + +ProfileInfo::ProfileInfo() +{ + profileBlock = nullptr; +} +ProfileInfo::~ProfileInfo() +{ + profileBlock.reset(nullptr); +} +ProfileInfo::ProfileInfo(const ProfileInfo& profileInfo) +{ + *this = profileInfo; +} +ProfileInfo& ProfileInfo::operator=(const ProfileInfo& profileInfo) +{ + if (this == &profileInfo) { + return *this; + } + this->versionCode = profileInfo.versionCode; + this->versionName = profileInfo.versionName; + this->uuid = profileInfo.uuid; + this->type = profileInfo.type; + this->distributionType = profileInfo.distributionType; + this->bundleInfo = profileInfo.bundleInfo; + this->acls = profileInfo.acls; + this->permissions = profileInfo.permissions; + this->debugInfo = profileInfo.debugInfo; + this->issuer = profileInfo.issuer; + this->appId = profileInfo.appId; + this->fingerprint = profileInfo.fingerprint; + this->appPrivilegeCapabilities = profileInfo.appPrivilegeCapabilities; + this->validity = profileInfo.validity; + this->metadatas = profileInfo.metadatas; + this->profileBlockLength = profileInfo.profileBlockLength; + (this->profileBlock).reset(nullptr); + if (profileInfo.profileBlockLength != 0 && profileInfo.profileBlock != nullptr) { + this->profileBlock = std::make_unique(profileInfo.profileBlockLength); + unsigned char* profileBlockData = (this->profileBlock).get(); + unsigned char* originalProfile = profileInfo.profileBlock.get(); + if (profileBlockData == nullptr) { + return *this; + } + std::copy(originalProfile, originalProfile + profileInfo.profileBlockLength, profileBlockData); + } + this->appServiceCapabilities = profileInfo.appServiceCapabilities; + this->organization = profileInfo.organization; + return *this; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/profile/src/profile_sign_tool.cpp b/binary_sign_tool/profile/src/profile_sign_tool.cpp new file mode 100644 index 00000000..7867a207 --- /dev/null +++ b/binary_sign_tool/profile/src/profile_sign_tool.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "profile_sign_tool.h" +#include "signer_factory.h" +#include "local_signer.h" +#include "localization_adapter.h" +#include "file_utils.h" +#include "pkcs7_data.h" +#include "verify_hap_openssl_utils.h" +#include "signature_tools_errno.h" + +namespace OHOS { +namespace SignatureTools { + +int ProfileSignTool::GenerateP7b(LocalizationAdapter& adapter, const std::string& content, std::string& ret) +{ + std::unique_ptr signerFactory = std::make_unique(); + std::shared_ptr signer(signerFactory->GetSigner(adapter)); + if (signer == NULL) { + SIGNATURE_TOOLS_LOGE("signer is NULL, get signer failed"); + return INVALIDPARAM_ERROR; + } + const std::string sigAlg = adapter.GetSignAlg(); + // ret is the generated p7b data + return SignProfile(content, signer, sigAlg, ret); +} + +/** +* @param content content to sign +* @param signer signer +* @param sigAlg sign algorithm only SHAwith256 or SHAwith384 +* @param ret signed data +* @return 0:success <0:error +*/ +int ProfileSignTool::SignProfile(const std::string& content, const std::shared_ptr& signer, + const std::string& sigAlg, std::string& ret) +{ + PKCS7Data p7Data; + int result = RET_OK; + result = p7Data.Sign(content, signer, sigAlg, ret); + if (result < 0) { + SIGNATURE_TOOLS_LOGE("SignProfile faild!"); + return SIGN_ERROR; + } + PKCS7Data p7DataVerify; + result = p7DataVerify.Parse(ret); + if (result < 0) { + SIGNATURE_TOOLS_LOGE("parse p7b failed"); + return PARSE_ERROR; + } + result = p7DataVerify.Verify(); + if (result < 0) { + SIGNATURE_TOOLS_LOGE("verify p7b failed"); + return VERIFY_ERROR; + } + return result; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/profile/src/profile_verify.cpp b/binary_sign_tool/profile/src/profile_verify.cpp new file mode 100644 index 00000000..7a09a1f8 --- /dev/null +++ b/binary_sign_tool/profile/src/profile_verify.cpp @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "nlohmann/json.hpp" +#include "signature_tools_log.h" +#include "signature_tools_errno.h" +#include "profile_verify.h" + +using namespace std; +using namespace nlohmann; + +namespace { +const string KEY_VERSION_CODE = "version-code"; +const string KEY_VERSION_NAME = "version-name"; +const string KEY_UUID = "uuid"; +const string KEY_TYPE = "type"; +const string KEY_APP_DIST_TYPE = "app-distribution-type"; +const string KEY_BUNDLE_INFO = "bundle-info"; +const string KEY_DEVELOPER_ID = "developer-id"; +const string KEY_DEVELOPMENT_CERTIFICATE = "development-certificate"; +const string KEY_DISTRIBUTION_CERTIFICATE = "distribution-certificate"; +const string KEY_BUNDLE_NAME = "bundle-name"; +const string KEY_APL = "apl"; +const string KEY_APP_FEATURE = "app-feature"; +const string KEY_ACLS = "acls"; +const string KEY_ALLOWED_ACLS = "allowed-acls"; +const string KEY_PERMISSIONS = "permissions"; +const string KEY_DATA_GROUP_IDS = "data-group-ids"; +const string KEY_RESTRICTED_PERMISSIONS = "restricted-permissions"; +const string KEY_RESTRICTED_CAPABILITIES = "restricted-capabilities"; +const string KEY_DEBUG_INFO = "debug-info"; +const string KEY_DEVICE_ID_TYPE = "device-id-type"; +const string KEY_DEVICE_IDS = "device-ids"; +const string KEY_ISSUER = "issuer"; +const string KEY_APP_PRIVILEGE_CAPABILITIES = "app-privilege-capabilities"; +const string KEY_APP_SERVICE_CAPABILITIES = "app-service-capabilities"; +const string VALUE_TYPE_RELEASE = "release"; +const string VALUE_TYPE_DEBUG = "debug"; +const string VALUE_DIST_TYPE_APP_GALLERY = "app_gallery"; +const string VALUE_DIST_TYPE_ENTERPRISE = "enterprise"; +const string VALUE_DIST_TYPE_ENTERPRISE_NORMAL = "enterprise_normal"; +const string VALUE_DIST_TYPE_ENTERPRISE_MDM = "enterprise_mdm"; +const string VALUE_DIST_TYPE_OS_INTEGRATION = "os_integration"; +const string VALUE_DIST_TYPE_CROWDTESTING = "crowdtesting"; +const string VALUE_DEVICE_ID_TYPE_UDID = "udid"; +const string VALUE_VALIDITY = "validity"; +const string VALUE_NOT_BEFORE = "not-before"; +const string VALUE_NOT_AFTER = "not-after"; +// reserved field +const string KEY_BASEAPP_INFO = "baseapp-info"; +const string KEY_PACKAGE_NAME = "package-name"; +const string KEY_PACKAGE_CERT = "package-cert"; +const string KEY_APP_IDENTIFIER = "app-identifier"; +const string GENERIC_BUNDLE_NAME = ".*"; + +inline void GetStringIfExist(const json& obj, const string& key, string& out) +{ + if (obj.find(key.c_str()) != obj.end() && obj[key.c_str()].is_string()) { + obj[key.c_str()].get_to(out); + } +} +inline void GetInt32IfExist(const json& obj, const string& key, int32_t& out) +{ + if (obj.find(key.c_str()) != obj.end() && obj[key.c_str()].is_number_integer()) { + obj[key.c_str()].get_to(out); + } +} +inline void GetInt64IfExist(const json& obj, const string& key, int64_t& out) +{ + if (obj.find(key.c_str()) != obj.end() && obj[key.c_str()].is_number_integer()) { + obj[key.c_str()].get_to(out); + } +} +inline void GetStringArrayIfExist(const json& obj, const string& key, vector& out) +{ + if (obj.find(key.c_str()) != obj.end() && obj[key.c_str()].is_array()) { + for (auto& item : obj[key.c_str()]) { + if (item.is_string()) { + out.push_back(item.get()); + } + } + } +} +inline bool IsObjectExist(const json& obj, const string& key) +{ + return obj.find(key.c_str()) != obj.end() && obj[key.c_str()].is_object(); +} +} // namespace +namespace OHOS { +namespace SignatureTools { +const std::map distTypeMap = { + {VALUE_DIST_TYPE_APP_GALLERY, AppDistType::APP_GALLERY}, + {VALUE_DIST_TYPE_ENTERPRISE, AppDistType::ENTERPRISE}, + {VALUE_DIST_TYPE_ENTERPRISE_NORMAL, AppDistType::ENTERPRISE_NORMAL}, + {VALUE_DIST_TYPE_ENTERPRISE_MDM, AppDistType::ENTERPRISE_MDM}, + {VALUE_DIST_TYPE_OS_INTEGRATION, AppDistType::OS_INTEGRATION}, + {VALUE_DIST_TYPE_CROWDTESTING, AppDistType::CROWDTESTING} +}; + +void ParseType(const json& obj, ProfileInfo& out) +{ + string type; + GetStringIfExist(obj, KEY_TYPE, type); + /* If not release, then it's debug */ + if (type == VALUE_TYPE_RELEASE) + out.type = RELEASE; + else if (type == VALUE_TYPE_DEBUG) + out.type = DEBUG; + else out.type = NONE_PROVISION_TYPE; +} +void ParseAppDistType(const json& obj, ProfileInfo& out) +{ + string distType; + GetStringIfExist(obj, KEY_APP_DIST_TYPE, distType); + auto ite = distTypeMap.find(distType); + if (ite != distTypeMap.end()) { + out.distributionType = static_cast(distTypeMap.at(distType)); + return; + } + out.distributionType = AppDistType::NONE_TYPE; +} +void ParseBundleInfo(const json& obj, ProfileInfo& out) +{ + if (IsObjectExist(obj, KEY_BUNDLE_INFO)) { + const auto& bundleInfo = obj[KEY_BUNDLE_INFO]; + GetStringIfExist(bundleInfo, KEY_DEVELOPER_ID, out.bundleInfo.developerId); + GetStringIfExist(bundleInfo, KEY_DEVELOPMENT_CERTIFICATE, + out.bundleInfo.developmentCertificate); + GetStringIfExist(bundleInfo, KEY_DISTRIBUTION_CERTIFICATE, + out.bundleInfo.distributionCertificate); + GetStringIfExist(bundleInfo, KEY_BUNDLE_NAME, out.bundleInfo.bundleName); + GetStringIfExist(bundleInfo, KEY_APL, out.bundleInfo.apl); + GetStringIfExist(bundleInfo, KEY_APP_FEATURE, out.bundleInfo.appFeature); + GetStringIfExist(bundleInfo, KEY_APP_IDENTIFIER, out.bundleInfo.appIdentifier); + GetStringArrayIfExist(bundleInfo, KEY_DATA_GROUP_IDS, out.bundleInfo.dataGroupIds); + } +} +void ParseAcls(const json& obj, ProfileInfo& out) +{ + if (IsObjectExist(obj, KEY_ACLS)) { + const auto& acls = obj[KEY_ACLS]; + GetStringArrayIfExist(acls, KEY_ALLOWED_ACLS, out.acls.allowedAcls); + } +} +void ParsePermissions(const json& obj, ProfileInfo& out) +{ + if (IsObjectExist(obj, KEY_PERMISSIONS)) { + const auto& permissions = obj[KEY_PERMISSIONS]; + GetStringArrayIfExist(permissions, KEY_RESTRICTED_PERMISSIONS, + out.permissions.restrictedPermissions); + GetStringArrayIfExist(permissions, KEY_RESTRICTED_CAPABILITIES, + out.permissions.restrictedCapabilities); + } +} +void ParseDebugInfo(const json& obj, ProfileInfo& out) +{ + if (IsObjectExist(obj, KEY_DEBUG_INFO)) { + GetStringIfExist(obj[KEY_DEBUG_INFO], KEY_DEVICE_ID_TYPE, out.debugInfo.deviceIdType); + GetStringArrayIfExist(obj[KEY_DEBUG_INFO], KEY_DEVICE_IDS, out.debugInfo.deviceIds); + } +} +void ParseValidity(const json& obj, Validity& out) +{ + if (IsObjectExist(obj, VALUE_VALIDITY)) { + GetInt64IfExist(obj[VALUE_VALIDITY], VALUE_NOT_BEFORE, out.notBefore); + GetInt64IfExist(obj[VALUE_VALIDITY], VALUE_NOT_AFTER, out.notAfter); + } +} +void ParseMetadata(const json& obj, ProfileInfo& out) +{ + if (IsObjectExist(obj, KEY_BASEAPP_INFO)) { + const auto& baseAppInfo = obj[KEY_BASEAPP_INFO]; + Metadata metadata; + metadata.name = KEY_PACKAGE_NAME; + GetStringIfExist(baseAppInfo, KEY_PACKAGE_NAME, metadata.value); + out.metadatas.emplace_back(metadata); + metadata.name = KEY_PACKAGE_CERT; + GetStringIfExist(baseAppInfo, KEY_PACKAGE_CERT, metadata.value); + out.metadatas.emplace_back(metadata); + } +} +void from_json(const json& obj, ProfileInfo& out) +{ + if (!obj.is_object()) { + return; + } + GetInt32IfExist(obj, KEY_VERSION_CODE, out.versionCode); + GetStringIfExist(obj, KEY_VERSION_NAME, out.versionName); + GetStringIfExist(obj, KEY_UUID, out.uuid); + ParseType(obj, out); + ParseAppDistType(obj, out); + ParseBundleInfo(obj, out); + ParseAcls(obj, out); + ParsePermissions(obj, out); + ParseDebugInfo(obj, out); + GetStringIfExist(obj, KEY_ISSUER, out.issuer); + GetStringArrayIfExist(obj, KEY_APP_PRIVILEGE_CAPABILITIES, out.appPrivilegeCapabilities); + ParseValidity(obj, out.validity); + ParseMetadata(obj, out); + GetStringIfExist(obj, KEY_APP_SERVICE_CAPABILITIES, out.appServiceCapabilities); +} + +AppProvisionVerifyResult ReturnIfStringIsEmpty(const std::string& str, const std::string& errMsg) +{ + if (str.empty()) { + PrintErrorNumberMsg("PROVISION_INVALID_ERROR", PROVISION_INVALID_ERROR, errMsg); + return PROVISION_INVALID; + } + return PROVISION_OK; +} + +AppProvisionVerifyResult ReturnIfIntIsNonPositive(int num, const std::string& errMsg) +{ + if (num <= 0) { + PrintErrorNumberMsg("PROVISION_INVALID_ERROR", PROVISION_INVALID_ERROR, errMsg); + return PROVISION_INVALID; + } + return PROVISION_OK; +} + +static AppProvisionVerifyResult CheckProfileValidType(const ProfileInfo& info) +{ + if (info.type == ProvisionType::DEBUG) { + if (ReturnIfStringIsEmpty(info.bundleInfo.developmentCertificate, + "Tag development-certificate is empty.") != PROVISION_OK) { + return PROVISION_INVALID; + } + } else if (info.type == ProvisionType::RELEASE) { + if (ReturnIfIntIsNonPositive(info.distributionType, + "Tag app-distribution-type is empty.") != PROVISION_OK) { + return PROVISION_INVALID; + } + if (ReturnIfStringIsEmpty(info.bundleInfo.distributionCertificate, + "Tag distribution-certificate is empty.") != PROVISION_OK) { + return PROVISION_INVALID; + } + } else { + PrintErrorNumberMsg("PROVISION_INVALID_ERROR", PROVISION_INVALID_ERROR, + "The type field in the profile file is incorrect"); + return PROVISION_INVALID; + } + return PROVISION_OK; +} + +AppProvisionVerifyResult ParseProvision(const string& appProvision, ProfileInfo& info) +{ + if (ParseProfile(appProvision, info) != PROVISION_OK) { + return PROVISION_INVALID; + } + + if (CheckProfileValidType(info) != PROVISION_OK) { + return PROVISION_INVALID; + } + return PROVISION_OK; +} + +AppProvisionVerifyResult ParseAndVerify(const string& appProvision, ProfileInfo& info) +{ + SIGNATURE_TOOLS_LOGD("Enter HarmonyAppProvision Verify"); + AppProvisionVerifyResult ret = ParseProvision(appProvision, info); + if (ret != PROVISION_OK) { + return ret; + } + SIGNATURE_TOOLS_LOGD("Leave HarmonyAppProvision Verify"); + return PROVISION_OK; +} +AppProvisionVerifyResult ParseProfile(const std::string& appProvision, ProfileInfo& info) +{ + json obj = json::parse(appProvision, nullptr, false); + if (obj.is_discarded() || (!obj.is_structured())) { + std::string errStr = "invalid json object, parse provision failed, json: " + appProvision; + PrintErrorNumberMsg("PROVISION_INVALID_ERROR", PROVISION_INVALID_ERROR, errStr.c_str()); + return PROVISION_INVALID; + } + obj.get_to(info); + return PROVISION_OK; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/signature_tools.gni b/binary_sign_tool/signature_tools.gni new file mode 100644 index 00000000..b43efcc1 --- /dev/null +++ b/binary_sign_tool/signature_tools.gni @@ -0,0 +1,24 @@ +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +signature_tools_root_path = "//developtools/hapsigner/binary_sign_tool" +signature_tools_utils = "${signature_tools_root_path}/utils" +signature_tools_cmd = "${signature_tools_root_path}/cmd" +signature_tools_error = "${signature_tools_root_path}/error" +# signature_tools_codesigning = "${signature_tools_root_path}/codesigning" +signature_tools_common = "${signature_tools_root_path}/common" +signature_tools_hap = "${signature_tools_root_path}/hap" +signature_tools_profile = "${signature_tools_root_path}/profile" +signature_tools_signer = "${signature_tools_root_path}/signer" +signature_tools_api = "${signature_tools_root_path}/api" +# signature_tools_test = "//developtools/hapsigner/hapsigntool_cpp_test" diff --git a/binary_sign_tool/signer/include/local_signer.h b/binary_sign_tool/signer/include/local_signer.h new file mode 100644 index 00000000..a301db9f --- /dev/null +++ b/binary_sign_tool/signer/include/local_signer.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SINATURETOOLS_LOCAL_SIGNER_H +#define SINATURETOOLS_LOCAL_SIGNER_H + +#include "openssl/x509.h" +#include "signer.h" + +namespace OHOS { +namespace SignatureTools { + +class LocalSigner : public Signer { +public: + /** + * Create local signer. + * + * @param keyPair Private key to sign + * @param certificates Cert chain to sign + */ + LocalSigner(EVP_PKEY* keyPair, STACK_OF(X509)* certificates); + ~LocalSigner()override; + /** + * GetCrls. + * + * @return crls + */ + STACK_OF(X509_CRL)* GetCrls()const override; + /** + * GetCertificates. + * + * @return Certificates + */ + STACK_OF(X509)* GetCertificates()const override; + std::string GetSignature(const std::string& data, const std::string& signAlg)const override; +private: + /** + * key pair. + */ + EVP_PKEY* m_keyPair; + /** + * certchain. + */ + STACK_OF(X509)* m_certificates; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SINATURETOOLS_LOCAL_SIGNER_H \ No newline at end of file diff --git a/binary_sign_tool/signer/include/signer.h b/binary_sign_tool/signer/include/signer.h new file mode 100644 index 00000000..ca0ad2da --- /dev/null +++ b/binary_sign_tool/signer/include/signer.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SINATURETOOLS_ISINGER_H +#define SINATURETOOLS_ISINGER_H + +#include +#include "openssl/x509.h" + +namespace OHOS { +namespace SignatureTools { + +/** + * Signer. + * + */ +class Signer { +public: + virtual STACK_OF(X509_CRL)* GetCrls()const = 0; + virtual STACK_OF(X509)* GetCertificates()const = 0; + virtual ~Signer() = default; + virtual std::string GetSignature(const std::string& data, const std::string& signAlg)const = 0; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SINATURETOOLS_ISINGER_H \ No newline at end of file diff --git a/binary_sign_tool/signer/include/signer_factory.h b/binary_sign_tool/signer/include/signer_factory.h new file mode 100644 index 00000000..254176bb --- /dev/null +++ b/binary_sign_tool/signer/include/signer_factory.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SINATURETOOLS_SIGNER_FACTORY_H +#define SINATURETOOLS_SIGNER_FACTORY_H + +#include + +#include "local_signer.h" +#include "localization_adapter.h" +#include "param_constants.h" + +namespace OHOS { +namespace SignatureTools { + +typedef struct RemoteSignerParamTypeSt { + const char* data; + size_t len; +} RemoteSignerParamType; + +typedef Signer* (*RemoteSignerCreator)(RemoteSignerParamType, + RemoteSignerParamType, + RemoteSignerParamType, + RemoteSignerParamType, + RemoteSignerParamType); + +class SignerFactory { +public: + SignerFactory() = default; + ~SignerFactory() = default; + + std::shared_ptr GetSigner(LocalizationAdapter& adapter) const; + +private: + std::shared_ptr LoadRemoteSigner(LocalizationAdapter& adapter) const; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif \ No newline at end of file diff --git a/binary_sign_tool/signer/src/local_signer.cpp b/binary_sign_tool/signer/src/local_signer.cpp new file mode 100644 index 00000000..922918dc --- /dev/null +++ b/binary_sign_tool/signer/src/local_signer.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "signature_tools_log.h" +#include "pkcs7_data.h" +#include "constant.h" +#include "local_signer.h" + +namespace OHOS { +namespace SignatureTools { +/** +* Create local signer. +* +* @param keyPair Private key to sign +* @param certificates Cert chain to sign +*/ +LocalSigner::LocalSigner(EVP_PKEY* keyPair, STACK_OF(X509)* certificates) :m_keyPair(keyPair), +m_certificates(certificates) +{ + bool check = m_keyPair == NULL || + PKCS7Data::SortX509Stack(m_certificates) < 0 || + X509_check_private_key(sk_X509_value(m_certificates, 0), m_keyPair) != 1; + if (check) { + SIGNATURE_TOOLS_LOGW("Warning: invalid local signer!\n"); + sk_X509_pop_free(m_certificates, X509_free); + m_certificates = NULL; + } +} +LocalSigner::~LocalSigner() +{ + if (m_keyPair) { + EVP_PKEY_free(m_keyPair); + m_keyPair = NULL; + } + if (m_certificates) { + sk_X509_pop_free(m_certificates, X509_free); + m_certificates = NULL; + } +} +STACK_OF(X509_CRL)* LocalSigner::GetCrls() const +{ + return NULL; +} + +static X509* X509Dup(const X509* x509) +{ + return X509_dup(const_cast(x509)); +} + +STACK_OF(X509)* LocalSigner::GetCertificates() const +{ + if (m_certificates == NULL) { + return m_certificates; + } + return sk_X509_deep_copy(m_certificates, X509Dup, X509_free); +} +std::string LocalSigner::GetSignature(const std::string& data, const std::string& signAlg) const +{ + EVP_MD_CTX* hashCtx = NULL; + EVP_PKEY_CTX* privateKeyCtx = NULL; + unsigned char* sigResult = NULL; + const EVP_MD* hash = NULL; + size_t sigLen; + std::string ret; + + if (signAlg == SIGN_ALG_SHA256) { + hash = EVP_sha256(); + } else if (signAlg == SIGN_ALG_SHA384) { + hash = EVP_sha384(); + } else { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, + signAlg + "is invalid sigAlg, please use SHA256withECDSA/SHA384withECDSA, sign failed"); + return ret; + } + + /* calculate signature value */ + bool result = !(hashCtx = EVP_MD_CTX_new()) || + (EVP_DigestSignInit(hashCtx, &privateKeyCtx, hash, NULL, m_keyPair) <= 0) || + (EVP_DigestSignUpdate(hashCtx, data.data(), data.size()) <= 0) || + (EVP_DigestSignFinal(hashCtx, NULL, &sigLen) <= 0) || + !(sigResult = reinterpret_cast(OPENSSL_malloc(sigLen))) || + (EVP_DigestSignFinal(hashCtx, sigResult, &sigLen) <= 0); + if (result) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "compute signature value failed"); + goto err; + } + ret.assign(reinterpret_cast(sigResult), sigLen); +err: + OPENSSL_free(sigResult); + EVP_MD_CTX_free(hashCtx); + return ret; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/signer/src/signer_factory.cpp b/binary_sign_tool/signer/src/signer_factory.cpp new file mode 100644 index 00000000..91921d0d --- /dev/null +++ b/binary_sign_tool/signer/src/signer_factory.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "signer_factory.h" +#include "dynamic_lib_handle.h" + +namespace OHOS { +namespace SignatureTools { + +std::shared_ptr SignerFactory::GetSigner(LocalizationAdapter& adapter)const +{ + if (adapter.IsRemoteSigner()) { + return LoadRemoteSigner(adapter); + } + + EVP_PKEY* keyPair = adapter.GetAliasKey(false); + if (keyPair == NULL) { + SIGNATURE_TOOLS_LOGE("key is NULL, get signer failed"); + adapter.ResetPwd(); + return NULL; + } + adapter.ResetPwd(); + STACK_OF(X509)*certs = adapter.GetSignCertChain(); + std::shared_ptr signer = std::make_shared(keyPair, certs); + return signer; +} + +std::shared_ptr SignerFactory::LoadRemoteSigner(LocalizationAdapter& adapter) const +{ + std::string keyAlias = adapter.GetOptions()->GetString(ParamConstants::PARAM_BASIC_PRIVATE_KEY); + std::string signServer = adapter.GetOptions()->GetString(ParamConstants::PARAM_REMOTE_SERVER); + std::string signerPlugin = adapter.GetOptions()->GetString(ParamConstants::PARAM_REMOTE_SIGNERPLUGIN); + std::string onlineAuthMode = adapter.GetOptions()->GetString(ParamConstants::PARAM_REMOTE_ONLINEAUTHMODE); + std::string username = adapter.GetOptions()->GetString(ParamConstants::PARAM_REMOTE_USERNAME); + char* userPwd = adapter.GetOptions()->GetChars(ParamConstants::PARAM_REMOTE_USERPWD); + + // open so + DynamicLibHandle::handle = dlopen(signerPlugin.c_str(), RTLD_NOW | RTLD_GLOBAL); + if (!DynamicLibHandle::handle) { + PrintErrorNumberMsg("LoadRemoteSigner", RET_FAILED, dlerror()); + return nullptr; + } + + // clear previous error + dlerror(); + + // get "Create" function + RemoteSignerCreator remoteSignerCreator = (RemoteSignerCreator)dlsym(DynamicLibHandle::handle, "Create"); + char* error = nullptr; + if ((error = dlerror()) != NULL) { + SIGNATURE_TOOLS_LOGE("%s", error); + return nullptr; + } + + RemoteSignerParamType keyAliasType{keyAlias.c_str(), keyAlias.size()}; + RemoteSignerParamType signServerType{signServer.c_str(), signServer.size()}; + RemoteSignerParamType onlineAuthModeType{onlineAuthMode.c_str(), onlineAuthMode.size()}; + RemoteSignerParamType usernameType{username.c_str(), username.size()}; + RemoteSignerParamType userPwdType{userPwd, strlen(userPwd)}; + + Signer* signer = remoteSignerCreator(keyAliasType, signServerType, onlineAuthModeType, usernameType, userPwdType); + + for (size_t i = 0; i < strlen(userPwd); i++) { + userPwd[i] = 0; + } + + std::shared_ptr remoteSigner(signer); + return remoteSigner; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/utils/include/file_utils.h b/binary_sign_tool/utils/include/file_utils.h new file mode 100644 index 00000000..28b4a8bd --- /dev/null +++ b/binary_sign_tool/utils/include/file_utils.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_FILE_UTILS_H +#define SIGNATRUETOOLS_FILE_UTILS_H +#include +#include +#include +#include +#include +#include +#include + +#include "byte_buffer.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { + +class FileUtils { +public: + static const int NUM_TWO; + static const int NUM_THREE; + static const int NUM_FOUR; + static const std::string LIBS_PATH_PREFIX; + static constexpr int FILE_BUFFER_BLOCK = 1024 * 1024; + FileUtils() = delete; + // judge is or not empty + static bool IsEmpty(std::string cs); + // get file suffix + static std::string GetSuffix(std::string filePath); + // verify file type + static bool ValidFileType(const std::string& filePath, const std::initializer_list types); + static bool IsValidFile(std::string file); + /** +* write content to output file +* @param content data to write +* @param output path +* @return 0:success +*/ + static int Write(const std::string& content, const std::string& output); + /** +* Read byte from input stream. +* +* @param input Input stream +* @param ret File content +* @return 0:success <0:error +*/ + static int Read(std::ifstream& input, std::string& ret); + /** +*Read byte from input file. +* +* @param file Which file to read +* @param ret byte content +* @return 0:success <0:error +*/ + static int ReadFile(const std::string& path, std::string& ret); + static bool ReadFileToByteBuffer(const std::string& file, ByteBuffer& buffer); + static bool isElfFile(const std::string& filePath); + /** + * Read byte from input file. + * + * @param file input file + * @param offset offset + * @param length length + * @param ret data bytes + * @return 0:success <0:error + */ + static int ReadFileByOffsetAndLength(std::ifstream& file, size_t offset, size_t length, std::string& ret); + /** + * Read byte from input stream. + * + * @param input input stream + * @param offset offset + * @param length length + * @ret data bytes + * @return 0:success <0 :error + */ + static int ReadInputByOffsetAndLength(std::ifstream& input, size_t offset, size_t length, std::string& ret); + /** + * Read byte from input stream. + * + * @param input InputStream + * @param length length + * @ret data bytes + * @return 0:success <0 :error + */ + static int ReadInputByLength(std::ifstream& input, size_t length, std::string& ret); + /** + * Write data in file to output stream + * + * @param inFile input file path. + * @param out output file path. + * @param offset file read offset + * @param size file read size + * @return true, if write successfully. + */ + static int WriteInputToOutPut(std::ifstream& input, std::ofstream& output, size_t length); + static bool WriteInputToOutPut(const std::string& input, const std::string& output); + + /** + * regex filename + * + * @param name filename + * @return boolean + */ + static bool IsRunnableFile(const std::string& name); + static int64_t GetFileLen(const std::string& file); + static void DelDir(const std::string& file); + static bool CopyTmpFileAndDel(const std::string& tmpFile, const std::string& output); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_FILE_UTILS_H \ No newline at end of file diff --git a/binary_sign_tool/utils/include/hash_utils.h b/binary_sign_tool/utils/include/hash_utils.h new file mode 100644 index 00000000..8fb54935 --- /dev/null +++ b/binary_sign_tool/utils/include/hash_utils.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGNATRUETOOLS_HASH_UTILS_H +#define SIGNATRUETOOLS_HASH_UTILS_H + +#include +#include + +namespace OHOS { +namespace SignatureTools { +enum class HashAlgs { + USE_NONE = 0, + USE_MD2 = 1, + USE_MD4 = 2, + USE_MD5 = 3, + USE_SHA1 = 4, + USE_SHA224 = 5, + USE_SHA256 = 6, + USE_SHA384 = 7, + USE_SHA512 = 8, + USE_RIPEMD160 = 9, +}; + +class HashUtils { +public: + HashUtils() = delete; + static int GetHashAlgsId(const std::string& algMethod); + static std::vector GetFileDigest(const std::string& inputFile, const std::string& algName); + static std::string GetHashAlgName(int algId); + static std::vector GetDigestFromBytes(const std::vector& fileBytes, int64_t length, + const std::string& algName); + +private: + static std::vector GetByteDigest(const std::string& str, int count, + const std::string& algMethod); + + static const int HASH_LEN = 4096; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATURETOOLS_HASH_UTILS_H \ No newline at end of file diff --git a/binary_sign_tool/utils/include/key_store_helper.h b/binary_sign_tool/utils/include/key_store_helper.h new file mode 100644 index 00000000..1c42441b --- /dev/null +++ b/binary_sign_tool/utils/include/key_store_helper.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_KEYSTOREHELPER_H +#define SIGNATRUETOOLS_KEYSTOREHELPER_H +#include +#include "openssl/ssl.h" +#include "openssl/pem.h" +#include "openssl/evp.h" +#include "openssl/pkcs12.h" +#include "openssl/pkcs7.h" +#include "signature_tools_log.h" +#include "verify_hap_openssl_utils.h" + +namespace OHOS { +namespace SignatureTools { +class KeyStoreHelper { +public: + KeyStoreHelper(); + ~KeyStoreHelper() = default; + int WriteKeyStore(EVP_PKEY* evpPkey, std::string& keyStorePath, char* keyStorePwd, + std::string alias, char* keyPwd); + int ReadKeyStore(std::string& keyStorePath, char* keyStorePwd, const std::string& alias, + char* keyPwd, EVP_PKEY** evpPkey); + int GetPublicKey(PKCS7* safe, const std::string& alias, char* pass, int passlen, EVP_PKEY** publickey); + int GetPrivateKey(PKCS7* safe, const std::string& alias, char* pass, int passlen, EVP_PKEY** keyPiar); + int SetCertPkcs12(X509* cert, PKCS12_SAFEBAG* bag, STACK_OF(PKCS12_SAFEBAG)* certBags, unsigned char* keyId, + unsigned int keyIdLen, const char* name, STACK_OF(PKCS7)** safes, + int certNid, int iter, const char* keyStorePwd); + int SetPkeyPkcs12(EVP_PKEY* pkey, PKCS12_SAFEBAG* bag, STACK_OF(PKCS12_SAFEBAG)* keyBags, + const char* name, STACK_OF(PKCS7)** safes, int iter, const char* keyPwd, + int keyType, int keyNid, unsigned char* keyId, unsigned int keyIdLen); + int GetAttrNid(PKCS12_SAFEBAG* bag, EVP_PKEY* pkey, int nid); + int FindKeyPair(PKCS12* p12, const std::string& alias, char* keyPwd, char* keyStorePwd, + EVP_PKEY** keyPiar, const std::string& keyStorePath); + int ParsePkcs12Safebag(PKCS12_SAFEBAG* bag, const char* pass, int passlen, STACK_OF(X509)* ocerts); + int ParsePkcs12Safebags(const STACK_OF(PKCS12_SAFEBAG)* bags, const char* pass, + int passlen, STACK_OF(X509)* ocerts); + int Pkcs12PasswordParse(PKCS12* p12, const char* keyStorePwd, const std::string& keyStoreFile); + int CreatePKCS12(PKCS12** p12, const std::string& charsStorePath, char* keyStorePwd, + char* keyPwd, const std::string& charsAlias, EVP_PKEY* evpPkey, X509* cert); + + bool InitX509(X509& cert, EVP_PKEY& evpPkey); + bool IsKeyStoreFileExist(std::string& keyStorePath); + bool SetX509Alias(int len, X509* x509, unsigned char* data); + bool GetPassWordStatus(); + + void SetNidMac(int& nidKey, int& iter, int& macStatus); + void SetPassWordStatus(bool status); + void SetIsRegen(bool autoCreate); + + EVP_PKEY* GenerateKeyPair(const std::string& algorithm, int keySize); + PKCS12* CreatePKCS12(const char* keyStorePwd, const char* keyPwd, const char* name, EVP_PKEY* pkey, X509* cert, + int keyNid, int certNid, int iter, int macStatus, int keyType, STACK_OF(PKCS7)** safes); + +private: + void KeyPairFree(EC_GROUP* group, EC_KEY* pkey, const std::string& Message); + void KeyPairFree(BIGNUM* bnSerial, X509_NAME* issuerName, X509_NAME* subjectName, + ASN1_INTEGER* ai, const std::string& Message); + void KeyPairFree(X509* cert, PKCS12* p12, BIO* bioOut, const std::string& Message); + void KeyPairFree(STACK_OF(X509)* ocerts, STACK_OF(PKCS12_SAFEBAG)* bags, char* name); + void KeyPairFree(STACK_OF(PKCS7)* safes, EVP_PKEY* publickey); + void KeyPairFree(STACK_OF(PKCS12_SAFEBAG)* bags, PKCS8_PRIV_KEY_INFO* p8, char* name); + void ResetKeyStatusvariable(); + void ResePwdLenvariable(); + void PrintAliasExistErrorMsg(const std::string& alias, const std::string& keyStorePath); + void SetPwdLenKeyStatus(char* pass, char* keyPass); + +private: + const int NID_PBE_CBC = 149; + const int NID_TRIPLEDES_CBC = 146; + + bool passWordStatus; + bool isRegen; + + int keyStorePwdLen; + int keyPairPwdLen; + int publicKeyStatus; + int privateKeyStatus; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif diff --git a/binary_sign_tool/utils/include/signature_info.h b/binary_sign_tool/utils/include/signature_info.h new file mode 100644 index 00000000..6df6a092 --- /dev/null +++ b/binary_sign_tool/utils/include/signature_info.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNERTOOLS_SIGNATURE_INFO_H +#define SIGNERTOOLS_SIGNATURE_INFO_H + +#include +#include "byte_buffer.h" + +namespace OHOS { +namespace SignatureTools { +struct OptionalBlock { + int32_t optionalType = 0; + ByteBuffer optionalBlockValue; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // HAP_SIGNATURE_INFO_H diff --git a/binary_sign_tool/utils/include/string_utils.h b/binary_sign_tool/utils/include/string_utils.h new file mode 100644 index 00000000..ae84c026 --- /dev/null +++ b/binary_sign_tool/utils/include/string_utils.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_STRINGUTILS_H +#define SIGNATRUETOOLS_STRINGUTILS_H + +#include +#include +#include + +#include "openssl/pem.h" +#include "openssl/x509.h" +#include "signature_tools_log.h" +#include "verify_hap_openssl_utils.h" + +namespace OHOS { +namespace SignatureTools { +class StringUtils { +public: + StringUtils() = delete; + static bool IsEmpty(const std::string& cs); + static bool ContainsCase(const std::vector &strs, const std::string& str); + static bool CaseCompare(const std::string& str1, const std::string& str2); + static std::vector SplitString(const std::string& str, char delimiter); + static std::string Trim(const std::string& str); + static std::string FormatLoading(std::string& dealStr); + static std::string Pkcs7ToString(PKCS7* p7); + static std::string x509CertToString(X509* cert); + static std::string SubjectToString(X509* cert); + static bool CheckStringToint(const std::string& in, int& out); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_STRINGUTILS_H \ No newline at end of file diff --git a/binary_sign_tool/utils/include/verify_cert_openssl_utils.h b/binary_sign_tool/utils/include/verify_cert_openssl_utils.h new file mode 100644 index 00000000..e9688e87 --- /dev/null +++ b/binary_sign_tool/utils/include/verify_cert_openssl_utils.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef HAP_CERT_VERIFY_OPENSSL_UTILS_H +#define HAP_CERT_VERIFY_OPENSSL_UTILS_H + +#include +#include + +#include "export_define.h" +#include "byte_buffer.h" +#include "pkcs7_context.h" + +namespace OHOS { +namespace SignatureTools { + +using CertSign = std::unordered_map; + +class VerifyCertOpensslUtils { +public: + VerifyCertOpensslUtils() = delete; + DLL_EXPORT static bool VerifyCrl(CertChain& certsChain, STACK_OF(X509_CRL)* crls, + Pkcs7Context& pkcs7Context); + + DLL_EXPORT static bool X509NameCompare(const X509_NAME* a, const X509_NAME* b); + DLL_EXPORT static X509* FindCertOfIssuer(X509* cert, CertSign& certVisitSign); + DLL_EXPORT static std::string GetDnToString(X509_NAME* name); + DLL_EXPORT static void GetTextFromX509Name(X509_NAME* name, int32_t nId, std::string& text); + DLL_EXPORT static X509_CRL* GetCrlBySignedCertIssuer(STACK_OF(X509_CRL)* crls, const X509* cert); + DLL_EXPORT static bool CheckSignTimeInValidPeriod(const ASN1_TYPE* signTime, + const ASN1_TIME* notBefore, const ASN1_TIME* notAfter); + DLL_EXPORT static void GenerateCertSignFromCertStack(STACK_OF(X509)* certs, CertSign& certVisitSign); + DLL_EXPORT static void ClearCertVisitSign(CertSign& certVisitSign); + DLL_EXPORT static bool GetCertsChain(CertChain& certsChain, CertSign& certVisitSign); + DLL_EXPORT static bool CertVerify(X509* cert, const X509* issuerCert); + DLL_EXPORT static bool CheckAsn1TimeIsValid(const ASN1_TIME* asn1Time); + DLL_EXPORT static bool CheckAsn1TypeIsValid(const ASN1_TYPE* asn1Type); + DLL_EXPORT static bool GetSubjectFromX509(const X509* cert, std::string& subject); + DLL_EXPORT static bool GetIssuerFromX509(const X509* cert, std::string& issuer); + DLL_EXPORT static bool VerifyCertChainPeriodOfValidity(CertChain& certsChain, + const ASN1_TYPE* signTime); +private: + static const int32_t OPENSSL_READ_CRL_LEN_EACH_TIME; + static const int32_t BASE64_ENCODE_LEN_OF_EACH_GROUP_DATA; + static const int32_t BASE64_ENCODE_PACKET_LEN; + static const uint32_t MIN_CERT_CHAIN_LEN_NEED_VERIFY_CRL; + static const int32_t OPENSSL_READ_CRL_MAX_TIME; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // HAP_CERT_VERIFY_OPENSSL_UTILS_H diff --git a/binary_sign_tool/utils/include/verify_hap_openssl_utils.h b/binary_sign_tool/utils/include/verify_hap_openssl_utils.h new file mode 100644 index 00000000..2f9ee640 --- /dev/null +++ b/binary_sign_tool/utils/include/verify_hap_openssl_utils.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef SIGNATRUETOOLS_VERIFY_OPENSSL_UTILS_H +#define SIGNATRUETOOLS_VERIFY_OPENSSL_UTILS_H +#include +#include + +#include "pkcs7_context.h" +#include "export_define.h" +#include "byte_buffer.h" +#include "openssl/evp.h" +#include "openssl/ossl_typ.h" +#include "openssl/pkcs7.h" +#include "openssl/safestack.h" +#include "digest_parameter.h" +#include "verify_cert_openssl_utils.h" + +namespace OHOS { +namespace SignatureTools { + +class VerifyHapOpensslUtils { +public: + VerifyHapOpensslUtils() = delete; + DLL_EXPORT static bool ParsePkcs7Package(const unsigned char packageData[], + uint32_t packageLen, Pkcs7Context& pkcs7Context); + DLL_EXPORT static bool GetCertChains(PKCS7* p7, Pkcs7Context& pkcs7Context); + + DLL_EXPORT static bool GetCrlStack(PKCS7* p7, STACK_OF(X509_CRL)* x509Crl); + DLL_EXPORT static bool VerifyPkcs7(Pkcs7Context& pkcs7Context); + + static void GetOpensslErrorMessage(); + +private: + DLL_EXPORT static bool VerifyPkcs7SignedData(Pkcs7Context& pkcs7Context); + DLL_EXPORT static bool VerifySignInfo(STACK_OF(PKCS7_SIGNER_INFO)* signerInfoStack, + BIO* p7Bio, int32_t signInfoNum, Pkcs7Context& pkcs7Context); + static bool VerifyCertChain(CertChain& certsChain, PKCS7* p7, PKCS7_SIGNER_INFO* signInfo, + Pkcs7Context& pkcs7Context, CertSign& certVisitSign); + static bool GetContentInfo(const PKCS7* p7ContentInfo, ByteBuffer& content); + static bool CheckPkcs7SignedDataIsValid(const PKCS7* p7); + + static const int32_t OPENSSL_PKCS7_VERIFY_SUCCESS; + static const int32_t OPENSSL_ERR_MESSAGE_MAX_LEN; + static const int32_t OPENSSL_READ_DATA_MAX_TIME; + static const int32_t OPENSSL_READ_DATA_LEN_EACH_TIME; + static const int32_t MAX_OID_LENGTH; + static const std::string PKCS7_EXT_SHAWITHRSA_PSS; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_VERIFY_OPENSSL_UTILS_H diff --git a/binary_sign_tool/utils/signature_tools_utils.gni b/binary_sign_tool/utils/signature_tools_utils.gni new file mode 100644 index 00000000..7c2814dd --- /dev/null +++ b/binary_sign_tool/utils/signature_tools_utils.gni @@ -0,0 +1,23 @@ +# Copyright (c) 2025 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("../signature_tools.gni") +signature_tools_utils_include = [ "${signature_tools_utils}/include" ] + +signature_tools_utils_src = [ + "${signature_tools_utils}/src/verify_cert_openssl_utils.cpp", + "${signature_tools_utils}/src/file_utils.cpp", + "${signature_tools_utils}/src/key_store_helper.cpp", + "${signature_tools_utils}/src/string_utils.cpp", + "${signature_tools_utils}/src/verify_hap_openssl_utils.cpp", +] diff --git a/binary_sign_tool/utils/src/file_utils.cpp b/binary_sign_tool/utils/src/file_utils.cpp new file mode 100644 index 00000000..24ed0f97 --- /dev/null +++ b/binary_sign_tool/utils/src/file_utils.cpp @@ -0,0 +1,363 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "file_utils.h" +#include +#include +#include +#include +#include + +#include "string_utils.h" +#include "signature_tools_errno.h" + +namespace OHOS { +namespace SignatureTools { + +const int FileUtils::NUM_TWO = 2; +const int FileUtils::NUM_THREE = 3; +const int FileUtils::NUM_FOUR = 4; +const std::string FileUtils::LIBS_PATH_PREFIX = "libs/"; +const char ELF_MAGIC[] = { '\x7f', 'E', 'L', 'F' }; +bool FileUtils::IsEmpty(std::string cs) +{ + if (cs.length() == 0) { + return true; + } + return false; +} + +std::string FileUtils::GetSuffix(std::string filePath) +{ + if (filePath.empty()) { + return ""; + } + size_t lastDotPosition = filePath.rfind("."); + bool positionFlag = (lastDotPosition == std::string::npos) || (lastDotPosition == filePath.size() - 1); + if (positionFlag) { + return ""; + } + return filePath.substr(lastDotPosition + 1); +} + +bool FileUtils::ValidFileType(const std::string& filePath, const std::initializer_list types) +{ + std::string suffix = GetSuffix(filePath); + bool flag = suffix.empty() || (StringUtils::ContainsCase(types, suffix) == false); + if (flag) { + PrintErrorNumberMsg("NOT_SUPPORT_ERROR", NOT_SUPPORT_ERROR, "Not support file: " + filePath); + return false; + } + return true; +} + +int FileUtils::Write(const std::string& content, const std::string& output) +{ + std::ofstream outFile(output, std::ios::binary); + bool flag = (outFile.rdstate() != 0); + if (flag) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open output file: " + output + " failed"); + return IO_ERROR; + } + outFile.write(&content[0], content.size()); + if (outFile.rdstate() != 0) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "Failed to write data to output stream."); + return IO_ERROR; + } + return RET_OK; +} + +int FileUtils::Read(std::ifstream& input, std::string& ret) +{ + ret.clear(); + if (input.rdstate() != 0) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "invalid input stream"); + return IO_ERROR; + } + ret.clear(); + std::string buffer(FileUtils::FILE_BUFFER_BLOCK, 0); + while (input) { + input.read(&buffer[0], buffer.size()); + if (input.fail() && !input.eof()) { + SIGNATURE_TOOLS_LOGE("error occurred while reading data"); + return IO_ERROR; + } + ret.append(&buffer[0], input.gcount()); + } + return RET_OK; +} + +int FileUtils::ReadFile(const std::string& path, std::string& ret) +{ + std::ifstream file(path, std::ios::binary); + bool flag = (file.rdstate() != 0); + if (flag) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open input file: " + path + " failed"); + return IO_ERROR; + } + if (Read(file, ret) < 0) { + SIGNATURE_TOOLS_LOGE("read error!"); + return IO_ERROR; + } + return RET_OK; +} + +bool FileUtils::ReadFileToByteBuffer(const std::string& file, ByteBuffer& buffer) +{ + std::string ret; + if (ReadFile(file, ret) < 0) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, file + " not exist or can not read!"); + return false; + } + buffer.SetCapacity(static_cast(ret.size())); + buffer.PutData(ret.data(), ret.size()); + return true; +} + +bool FileUtils::isElfFile(const std::string& filePath) +{ + char magic[sizeof(ELF_MAGIC)]; + std::ifstream file(filePath, std::ios::binary); + if (!file) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open input file: " + filePath + " failed"); + return false; + } + file.read(magic, sizeof(ELF_MAGIC)); + return std::equal(magic, magic + sizeof(ELF_MAGIC), ELF_MAGIC); +} + +int FileUtils::ReadFileByOffsetAndLength(std::ifstream& file, size_t offset, size_t length, std::string& ret) +{ + if (length > INT_MAX) { + SIGNATURE_TOOLS_LOGE("Size cannot be greater than Integer max value: %zu", length); + return RET_FAILED; + } + if (ReadInputByOffsetAndLength(file, offset, length, ret) < 0) { + SIGNATURE_TOOLS_LOGE("Error readInputByOffsetAndLength"); + return IO_ERROR; + } + return RET_OK; +} + +int FileUtils::ReadInputByOffsetAndLength(std::ifstream& input, size_t offset, size_t length, std::string& ret) +{ + if (length > INT_MAX) { + SIGNATURE_TOOLS_LOGE("Size cannot be greater than Integer max value: %zu", length); + return -1; + } + input.seekg(offset); + if (ReadInputByLength(input, length, ret) < 0) { + SIGNATURE_TOOLS_LOGE("Error readInputByLength"); + return -1; + } + return RET_OK; +} + +int FileUtils::ReadInputByLength(std::ifstream& input, size_t length, std::string& ret) +{ + if (length > INT_MAX) { + SIGNATURE_TOOLS_LOGE("Size cannot be greater than Integer max value: %zu", length); + return -1; + } + if (input.rdstate() != 0) { + SIGNATURE_TOOLS_LOGE("Error input"); + return -1; + } + ret.clear(); + + char* buffer = new (std::nothrow)char[FILE_BUFFER_BLOCK]; + if (buffer == NULL) { + SIGNATURE_TOOLS_LOGE("create buffer error!"); + return -1; + } + size_t hasReadLen = 0; + + while (hasReadLen < length && input) { + int readLen = static_cast(std::min(length - hasReadLen, (size_t)FILE_BUFFER_BLOCK)); + input.read(buffer, readLen); + bool flag = (input.gcount() != readLen); + if (flag) { + delete[] buffer; + SIGNATURE_TOOLS_LOGE("read %zu bytes data less than %zu", hasReadLen, length); + return -1; + } + ret.append(buffer, readLen); + hasReadLen += readLen; + } + delete[] buffer; + if (hasReadLen != length) { + SIGNATURE_TOOLS_LOGE("read %zu bytes data less than %zu", hasReadLen, length); + return -1; + } + return RET_OK; +} + +int FileUtils::WriteInputToOutPut(std::ifstream& input, std::ofstream& output, size_t length) +{ + int result = RET_OK; + char* buf = new (std::nothrow)char[FILE_BUFFER_BLOCK]; + if (buf == NULL) { + SIGNATURE_TOOLS_LOGE("create buffer error!"); + return RET_FAILED; + } + + while (input) { + int min = std::min(static_cast(length), FILE_BUFFER_BLOCK); + input.read(buf, min); + if (input.fail() && !input.eof()) { + SIGNATURE_TOOLS_LOGE("read error!"); + delete[] buf; + return IO_ERROR; + } + length -= input.gcount(); + output.write(buf, input.gcount()); + if (!output.good()) { + SIGNATURE_TOOLS_LOGE("write error!"); + delete[] buf; + return IO_ERROR; + } + + if (length <= 0) { + break; + } + } + delete[] buf; + // After the file is written, datasize must be 0, so the if condition will never hold + if (length != 0) { + SIGNATURE_TOOLS_LOGE("written length error!"); + return IO_ERROR; + } + return result; +} + +bool FileUtils::WriteInputToOutPut(const std::string& input, const std::string& output) +{ + std::ifstream in(input, std::ios::binary); + std::ofstream out(output, std::ios::binary); + bool flag = (in.rdstate() != 0); + if (flag) { + SIGNATURE_TOOLS_LOGE("Failed to get input stream object!"); + return false; + } + flag = (out.rdstate() != 0); + if (flag) { + SIGNATURE_TOOLS_LOGE("Failed to get output stream object!"); + return false; + } + char* buffer = new char[FILE_BUFFER_BLOCK]; + while (!in.eof()) { + in.read(buffer, FILE_BUFFER_BLOCK); + + if (in.fail() && !in.eof()) { + SIGNATURE_TOOLS_LOGE("error occurred while reading data"); + delete[]buffer; + return false; + } + + std::streamsize readLen = in.gcount(); + if (readLen > 0) { + out.write(buffer, readLen); + } + + if (!out) { + SIGNATURE_TOOLS_LOGE("error occurred while writing data"); + delete[]buffer; + return false; + } + } + delete[]buffer; + return true; +} + +bool FileUtils::IsRunnableFile(const std::string& name) +{ + if (name.empty()) { + return false; + } + size_t dotPos = name.rfind('.'); + if (dotPos == std::string::npos) { + return false; + } + std::string suffix = name.substr(dotPos + 1); + if (suffix == "an" || suffix == "abc") { + return true; + } + std::string libDir = name.substr(0, LIBS_PATH_PREFIX.size()); + if (LIBS_PATH_PREFIX.compare(libDir) == 0) { + return true; + } + return false; +} + +bool FileUtils::IsValidFile(std::string file) +{ + std::filesystem::path filePath = file; + bool flag = std::filesystem::exists(filePath); + if (!flag) { + PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "'" + file + "' file is not exists"); + return false; + } + flag = std::filesystem::is_directory(filePath); + if (flag) { + PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "'" + file + "' file is a directory not file"); + return false; + } + return true; +} + +int64_t FileUtils::GetFileLen(const std::string& file) +{ + std::filesystem::path filePath = file; + bool flag = std::filesystem::exists(filePath) && std::filesystem::is_regular_file(filePath); + if (flag) { + return std::filesystem::file_size(filePath); + } + return -1; +} + +void FileUtils::DelDir(const std::string& file) +{ + std::filesystem::path filePath = file; + bool flag = std::filesystem::is_directory(filePath); + if (flag) { + for (auto& p : std::filesystem::recursive_directory_iterator(filePath)) { + DelDir(p.path()); + } + } + std::filesystem::remove(file); + return; +} + +bool FileUtils::CopyTmpFileAndDel(const std::string& tmpFile, const std::string& output) +{ + if (!std::filesystem::exists(tmpFile)) { + SIGNATURE_TOOLS_LOGE("Error: tmpFile not exists"); + return false; + } + if (tmpFile == output) { + return true; + } + bool ret = std::filesystem::copy_file(tmpFile, output, std::filesystem::copy_options::overwrite_existing); + if (!ret) { + SIGNATURE_TOOLS_LOGE("Error: copy tmpFile to output failed"); + return false; + } + if (!std::filesystem::remove(tmpFile)) { + SIGNATURE_TOOLS_LOGE("Error: remove tmpFile"); + return false; + } + return true; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/utils/src/hash_utils.cpp b/binary_sign_tool/utils/src/hash_utils.cpp new file mode 100644 index 00000000..69a1ae87 --- /dev/null +++ b/binary_sign_tool/utils/src/hash_utils.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include "fs_digest_utils.h" +#include "file_utils.h" +#include "hash_utils.h" + +namespace OHOS { +namespace SignatureTools { +int HashUtils::GetHashAlgsId(const std::string& algMethod) +{ + int result = static_cast(HashAlgs::USE_NONE); + if (0 == algMethod.compare("SHA-256")) { + result = static_cast(HashAlgs::USE_SHA256); + } + if (0 == algMethod.compare("SHA-384")) { + result = static_cast(HashAlgs::USE_SHA384); + } + if (0 == algMethod.compare("SHA-512")) { + result = static_cast(HashAlgs::USE_SHA512); + } + return result; +} + +std::string HashUtils::GetHashAlgName(int algId) +{ + if (static_cast(HashAlgs::USE_SHA256) == algId) { + return "SHA-256"; + } + if (static_cast(HashAlgs::USE_SHA384) == algId) { + return "SHA-384"; + } + if (static_cast(HashAlgs::USE_SHA512) == algId) { + return "SHA-512"; + } + return ""; +} + +std::vector HashUtils::GetFileDigest(const std::string& inputFile, const std::string& algName) +{ + std::vector result; + + std::ifstream input(inputFile, std::ios::binary); + if (0 != input.rdstate()) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "failed to get input stream object!"); + return std::vector(); + } + + char buffer[HASH_LEN] = { 0 }; + int num = 0; + std::map> hashMap; + + while (!input.eof()) { + input.read(buffer, HASH_LEN); + + if (input.fail() && !input.eof()) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "error occurred while reading data."); + return std::vector(); + } + + std::streamsize readLen = input.gcount(); + std::string str; + for (int i = 0; i < readLen; ++i) { + str.push_back(buffer[i]); + } + + std::vector dig = GetByteDigest(str, readLen, algName); + hashMap.emplace(num, dig); + ++num; + } + + if (hashMap.empty()) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "hashMap is empty."); + return std::vector(); + } + + DigestUtils fileDigestUtils(HASH_SHA256); + for (const auto& hashMapItem : hashMap) { + std::string str(hashMapItem.second.begin(), hashMapItem.second.end()); + fileDigestUtils.AddData(str); + } + std::string digest = fileDigestUtils.Result(DigestUtils::Type::BINARY); + for (std::string::size_type i = 0; i < digest.size(); i++) { + result.push_back(digest[i]); + } + return result; +} + +std::vector HashUtils::GetDigestFromBytes(const std::vector& fileBytes, int64_t length, + const std::string& algName) +{ + if (fileBytes.empty() || length <= 0) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "file bytes is empty."); + return std::vector(); + } + std::map> hashMap; + int64_t readLength = 0; + int64_t num = 0; + while (readLength < length) { + int64_t blockLength = length - readLength > HASH_LEN ? HASH_LEN : (length - readLength); + std::string readStr(fileBytes.begin() + readLength, fileBytes.begin() + readLength + blockLength); + std::vector dig = GetByteDigest(readStr, readStr.size(), algName); + hashMap.emplace(num, dig); + ++num; + readLength += readStr.size(); + } + if (hashMap.empty()) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "hashMap is empty."); + return std::vector(); + } + DigestUtils digestUtils(HASH_SHA256); + for (const auto& item : hashMap) { + std::string str(item.second.begin(), item.second.end()); + digestUtils.AddData(str); + } + std::string digest = digestUtils.Result(DigestUtils::Type::BINARY); + std::vector result; + for (std::string::size_type i = 0; i < digest.size(); i++) { + result.push_back(digest[i]); + } + return result; +} + +std::vector HashUtils::GetByteDigest(const std::string& str, int count, const std::string& algMethod) +{ + std::vector result; + DigestUtils digestUtils(HASH_SHA256); + digestUtils.AddData(str); + std::string digest = digestUtils.Result(DigestUtils::Type::BINARY); + for (std::string::size_type i = 0; i < digest.size(); i++) { + result.push_back(digest[i]); + } + return result; +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/utils/src/key_store_helper.cpp b/binary_sign_tool/utils/src/key_store_helper.cpp new file mode 100644 index 00000000..cfcf4049 --- /dev/null +++ b/binary_sign_tool/utils/src/key_store_helper.cpp @@ -0,0 +1,764 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "key_store_helper.h" +#include +#include "openssl/err.h" +#include "constant.h" +#include "signature_tools_errno.h" + +namespace OHOS { +namespace SignatureTools { +KeyStoreHelper::KeyStoreHelper() +{ + passWordStatus = true; + keyPairPwdLen = 0; + keyStorePwdLen = 0; + publicKeyStatus = RET_FAILED; + privateKeyStatus = RET_FAILED; +} + +void KeyStoreHelper::SetPassWordStatus(bool status) +{ + passWordStatus = status; +} + +void KeyStoreHelper::SetIsRegen(bool autoCreate) +{ + isRegen = autoCreate; +} + +bool KeyStoreHelper::GetPassWordStatus() +{ + return passWordStatus; +} + +void KeyStoreHelper::ResetKeyStatusvariable() +{ + publicKeyStatus = RET_FAILED; + privateKeyStatus = RET_FAILED; +} + +void KeyStoreHelper::ResePwdLenvariable() +{ + keyPairPwdLen = 0; + keyStorePwdLen = 0; +} + +void KeyStoreHelper::PrintAliasExistErrorMsg(const std::string& alias, const std::string& keyStorePath) +{ + if (!isRegen) { + PrintErrorNumberMsg("KEY_ALIAS_ERROR", KEY_ALIAS_ERROR, "keyAlias: '" + + alias + "' is not exist in" + keyStorePath); + } +} + +void KeyStoreHelper::KeyPairFree(EC_GROUP* group, EC_KEY* pkey, const std::string& Message) +{ + if (!Message.empty()) { + SIGNATURE_TOOLS_LOGE("%s", Message.c_str()); + } + + EC_GROUP_free(group); + group = nullptr; + + EC_KEY_free(pkey); + pkey = nullptr; +} + +void KeyStoreHelper::KeyPairFree(BIGNUM* bnSerial, X509_NAME* issuerName, X509_NAME* subjectName, + ASN1_INTEGER* ai, const std::string& Message) +{ + if (!Message.empty()) { + SIGNATURE_TOOLS_LOGE("%s", Message.c_str()); + } + + BN_free(bnSerial); + bnSerial = nullptr; + + ASN1_INTEGER_free(ai); + ai = nullptr; + + X509_NAME_free(issuerName); + issuerName = nullptr; + + X509_NAME_free(subjectName); + subjectName = nullptr; +} + +void KeyStoreHelper::KeyPairFree(X509* cert, PKCS12* p12, BIO* bioOut, const std::string& Message) +{ + if (!Message.empty()) { + SIGNATURE_TOOLS_LOGE("%s", Message.c_str()); + } + + X509_free(cert); + cert = nullptr; + + PKCS12_free(p12); + p12 = nullptr; + + BIO_free_all(bioOut); + bioOut = nullptr; +} + +void KeyStoreHelper::KeyPairFree(STACK_OF(X509)* ocerts, STACK_OF(PKCS12_SAFEBAG)* bags, char* name) +{ + sk_X509_pop_free(ocerts, X509_free); + ocerts = nullptr; + + sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); + bags = nullptr; + + free(name); + name = nullptr; +} + +void KeyStoreHelper::KeyPairFree(STACK_OF(PKCS7)* safes, EVP_PKEY* publickey) +{ + sk_PKCS7_pop_free(safes, PKCS7_free); + safes = nullptr; + + EVP_PKEY_free(publickey); + publickey = nullptr; +} + +void KeyStoreHelper::KeyPairFree(STACK_OF(PKCS12_SAFEBAG)* bags, PKCS8_PRIV_KEY_INFO* p8, char* name) +{ + sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); + bags = nullptr; + + PKCS8_PRIV_KEY_INFO_free(p8); + p8 = nullptr; + + free(name); + name = nullptr; +} + +bool KeyStoreHelper::InitX509(X509& cert, EVP_PKEY& evpPkey) +{ + BIGNUM* bnSerial = BN_new(); + X509_NAME* issuerName = X509_NAME_new(); + const EVP_MD* md = EVP_sha256(); + X509_NAME* subjectName = nullptr; + if (!bnSerial || !issuerName || !md) { + KeyPairFree(bnSerial, issuerName, subjectName, nullptr, "Failed to initialize the x509 info."); + return false; + } + ASN1_INTEGER* ai = BN_to_ASN1_INTEGER(bnSerial, NULL); + if (ai == NULL || issuerName == NULL) { + KeyPairFree(bnSerial, issuerName, subjectName, ai, "Failed to initialize the x509 structure."); + return false; + } + X509_set_serialNumber(&cert, ai); + X509_gmtime_adj(X509_get_notBefore(&cert), 0); + X509_gmtime_adj(X509_get_notAfter(&cert), (long)DEFAULT_VALIDITY_DAYS * ONE_DAY_TIME); + if (!X509_NAME_add_entry_by_txt(issuerName, "C", + MBSTRING_ASC, reinterpret_cast("US"), -1, -1, 0) + || !X509_NAME_add_entry_by_txt(issuerName, "O", + MBSTRING_ASC, reinterpret_cast("My Company"), -1, -1, 0) + || !X509_NAME_add_entry_by_txt(issuerName, "CN", + MBSTRING_ASC, reinterpret_cast("My Issuer"), -1, -1, 0)) { + KeyPairFree(bnSerial, issuerName, subjectName, ai, + "Failed to initialize the x509 structure.X509_NAME type"); + return false; + } + X509_set_issuer_name(&cert, issuerName); + subjectName = X509_NAME_dup(issuerName); + if (subjectName == NULL) { + KeyPairFree(bnSerial, issuerName, subjectName, ai, + "Failed to initialize the x509 structure.X509_NAME type"); + return false; + } + X509_set_subject_name(&cert, subjectName); + if (!X509_set_pubkey(&cert, &evpPkey)) { + KeyPairFree(bnSerial, issuerName, subjectName, ai, + "Failed to initialize the x509 structure.X509_NAME type"); + return false; + } + X509_set_version(&cert, DEFAULT_CERT_VERSION); + if (!X509_sign(&cert, &evpPkey, md)) { + KeyPairFree(bnSerial, issuerName, subjectName, ai, + "Failed to initialize the x509 structure.X509_NAME type"); + return false; + } + KeyPairFree(bnSerial, issuerName, subjectName, ai, ""); + return true; +} + +void KeyStoreHelper::SetPwdLenKeyStatus(char* pass, char* keyPass) +{ + ResePwdLenvariable(); + ResetKeyStatusvariable(); + + if (pass != nullptr) { + keyStorePwdLen = strlen(pass); + } + + if (keyPass != nullptr) { + keyPairPwdLen = strlen(keyPass); + } +} + +/* +* Function: Find the key pair in the PKCS12 structure by alias. +* Annotation: This function is to modify the openSSL interface "PKCS12_parse" and "find_friendly_name" functions, +* To fit java generated p12 files. +* find_friendly_name interface: Look for aliases in PKCS12 structures, one key pair for each PKCS12 structure. +* PKCS12_parse interface: Parse the PKCS12 structure, and obtain the key pair, +* one PKCS12 structure corresponds to one key pair. +* FindKeyPair interface: Get the stack structure "STACK_OF(PKCS7)" of PKCS7 in PKCS12 structure, and then traverse +* the "STACK_OF(PKCS7)" structure to get the public key and the private key by alias. +**/ +int KeyStoreHelper::FindKeyPair(PKCS12* p12, const std::string& alias, char* keyPwd, + char* keyStorePwd, EVP_PKEY** keyPiar, const std::string& keyStorePath) +{ + EVP_PKEY* publickey = nullptr; + STACK_OF(PKCS7)* safes = nullptr; + PKCS7* safe = nullptr; + + SetPwdLenKeyStatus(keyStorePwd, keyPwd); + + if ((safes = PKCS12_unpack_authsafes(p12)) == NULL) { + sk_PKCS7_pop_free(safes, PKCS7_free); + return RET_FAILED; + } + + for (int n = 0; n < sk_PKCS7_num(safes); n++) { + if ((publicKeyStatus == RET_OK) && (privateKeyStatus == RET_OK)) { + break; + } + + safe = sk_PKCS7_value(safes, n); + if (OBJ_obj2nid(safe->type) == NID_pkcs7_encrypted) { + if (publicKeyStatus != RET_OK) { + publicKeyStatus = GetPublicKey(safe, alias, keyStorePwd, keyStorePwdLen, &publickey); + } + + if (!GetPassWordStatus()) { + KeyPairFree(safes, publickey); + return RET_FAILED; + } + } else if (OBJ_obj2nid(safe->type) == NID_pkcs7_data && privateKeyStatus != RET_OK) { + privateKeyStatus = GetPrivateKey(safe, alias, keyPwd, keyPairPwdLen, keyPiar); + if (!GetPassWordStatus()) { + KeyPairFree(safes, publickey); + return RET_FAILED; + } + } + } + + if (((publicKeyStatus == RET_OK) && (privateKeyStatus == RET_OK)) + && (publickey != nullptr) && (*keyPiar != nullptr)) { + if (EVP_PKEY_copy_parameters(*keyPiar, publickey) != 1) { + KeyPairFree(safes, publickey); + SIGNATURE_TOOLS_LOGE("publickey and privatekey set EVP_PKEY struct failed"); + return RET_FAILED; + } + + KeyPairFree(safes, publickey); + return RET_OK; + } + PrintAliasExistErrorMsg(alias, keyStorePath); + KeyPairFree(safes, publickey); + return RET_FAILED; +} + +int KeyStoreHelper::GetPublicKey(PKCS7* safe, const std::string& alias, char* pass, int passlen, EVP_PKEY** publickey) +{ + char* name = NULL; + PKCS12_SAFEBAG* bag = nullptr; + STACK_OF(PKCS12_SAFEBAG)* bags = nullptr; + STACK_OF(X509)* ocerts = sk_X509_new_null(); + + bags = PKCS12_unpack_p7encdata(safe, pass, passlen); + if (bags == nullptr) { + PrintErrorNumberMsg("KEY_PASSWORD_ERROR", KEY_PASSWORD_ERROR, "'" + alias + "' keypair password error"); + KeyPairFree(ocerts, bags, name); + SetPassWordStatus(false); + return RET_FAILED; + } + + if (ParsePkcs12Safebags(bags, pass, passlen, ocerts) == RET_FAILED) { + PrintErrorNumberMsg("KEY_PASSWORD_ERROR", KEY_PASSWORD_ERROR, "'" + alias + "' keypair password error"); + KeyPairFree(ocerts, bags, name); + SetPassWordStatus(false); + return RET_FAILED; + } + for (int i = 0; i < sk_X509_num(ocerts); i++) { + bag = sk_PKCS12_SAFEBAG_value(bags, i); + name = PKCS12_get_friendlyname(bag); + if (strcmp(name, alias.c_str()) != 0) { + continue; + } + X509* cert = sk_X509_value(ocerts, i); + if (cert == nullptr) { + KeyPairFree(ocerts, bags, name); + return RET_FAILED; + } + *publickey = X509_get_pubkey(cert); + if (*publickey != nullptr) { + KeyPairFree(ocerts, bags, name); + return RET_OK; + } + } + + KeyPairFree(ocerts, bags, name); + return RET_FAILED; +} + +int KeyStoreHelper::GetPrivateKey(PKCS7* safe, const std::string& alias, char* pass, int passlen, EVP_PKEY** keyPiar) +{ + STACK_OF(PKCS12_SAFEBAG)* bags = nullptr; + PKCS12_SAFEBAG* bag = nullptr; + PKCS8_PRIV_KEY_INFO* p8 = nullptr; + char* name = NULL; + + bags = PKCS12_unpack_p7data(safe); + for (int m = 0; m < sk_PKCS12_SAFEBAG_num(bags); m++) { + bag = sk_PKCS12_SAFEBAG_value(bags, m); + if (PKCS12_SAFEBAG_get_nid(bag) != NID_pkcs8ShroudedKeyBag) { + continue; + } + name = PKCS12_get_friendlyname(bag); + if (strcmp(name, alias.c_str()) != 0) { + continue; + } + if ((p8 = PKCS12_decrypt_skey(bag, pass, passlen)) == NULL) { + PrintErrorNumberMsg("KEY_PASSWORD_ERROR", KEY_PASSWORD_ERROR, "'" + alias + + "' keypair password error"); + KeyPairFree(bags, p8, name); + SetPassWordStatus(false); + return RET_FAILED; + } + *keyPiar = EVP_PKCS82PKEY(p8); + if (*keyPiar == NULL) { + KeyPairFree(bags, p8, name); + return RET_FAILED; + } + + KeyPairFree(bags, p8, name); + return RET_OK; + } + + KeyPairFree(bags, p8, name); + return RET_FAILED; +} + +int KeyStoreHelper::WriteKeyStore(EVP_PKEY* evpPkey, std::string& keyStorePath, + char* keyStorePwd, std::string alias, char* keyPwd) +{ + X509* cert = X509_new(); + PKCS12* p12 = nullptr; + BIO* bioOut = nullptr; + + if (evpPkey == nullptr) { + KeyPairFree(cert, p12, bioOut, "The key pair pointer is null"); + return RET_FAILED; + } + + if (!InitX509(*cert, *evpPkey)) { + KeyPairFree(cert, p12, bioOut, "initialize x509 structure failed"); + return RET_FAILED; + } + + if (CreatePKCS12(&p12, keyStorePath, keyStorePwd, keyPwd, alias.c_str(), evpPkey, cert) == RET_FAILED) { + KeyPairFree(cert, p12, bioOut, "Create PKCS12 Structure Failed"); + return RET_FAILED; + } + + bioOut = BIO_new_file(keyStorePath.c_str(), "wb"); + if (bioOut == nullptr) { + KeyPairFree(cert, p12, bioOut, "Open file: '" + keyStorePath + "' failed"); + return RET_FAILED; + } + + if (i2d_PKCS12_bio(bioOut, p12) != 1) { + KeyPairFree(cert, p12, bioOut, "PKCS12 structure write File failure"); + return RET_FAILED; + } + + KeyPairFree(cert, p12, bioOut, ""); + return RET_OK; +} + +/* +* Function: Create a PKCS12 structured keystore, If the key stock is available, the key pair is appended. +* Annotation: This function is a modification of the OpenSSL "PKCS12_create" function, To fit java generated p12 files. +* PKCS12_create interface: A p12 file holds multiple PKCS12 structures, and a structure holds a key pair. +* CreatePKCS12 interface: A p12 file stores a PKCS12 structure,a PKCS12 structure stores multiplePKCS7 structures, +* and a PKCS7 structure corresponds to a key pair. +**/ +int KeyStoreHelper::CreatePKCS12(PKCS12** p12, const std::string& charsStorePath, char* keyStorePwd, + char* keyPwd, const std::string& charsAlias, EVP_PKEY* evpPkey, X509* cert) +{ + STACK_OF(PKCS7)* safes = nullptr; + PKCS12* acceptP12 = nullptr; + BIO* bioOut = BIO_new_file(charsStorePath.c_str(), "rb"); + if (bioOut != nullptr) { + acceptP12 = d2i_PKCS12_bio(bioOut, NULL); + if (acceptP12 == nullptr) { + return RET_FAILED; + } + if (Pkcs12PasswordParse(acceptP12, keyStorePwd, charsStorePath) == RET_FAILED) { + BIO_free_all(bioOut); + return RET_FAILED; + } + safes = PKCS12_unpack_authsafes(acceptP12); + } + + BIO_free_all(bioOut); + if (keyStorePwd == nullptr) { + *p12 = CreatePKCS12(keyStorePwd, keyPwd, charsAlias.c_str(), evpPkey, cert, 0, 0, 0, -1, 0, &safes); + } else { + *p12 = CreatePKCS12(keyStorePwd, keyPwd, charsAlias.c_str(), evpPkey, cert, 0, 0, 0, 0, 0, &safes); + } + + sk_PKCS7_pop_free(safes, PKCS7_free); + safes = nullptr; + PKCS12_free(acceptP12); + + if (*p12 == nullptr) { + return RET_FAILED; + } + return RET_OK; +} + +int KeyStoreHelper::ReadKeyStore(std::string& keyStorePath, char* keyStorePwd, const std::string& alias, + char* keyPwd, EVP_PKEY** evpPkey) +{ + X509* cert = nullptr; + PKCS12* p12 = nullptr; + BIO* bioOut = nullptr; + + bioOut = BIO_new_file(keyStorePath.c_str(), "rb"); + if (bioOut == nullptr) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + KeyPairFree(cert, p12, bioOut, "Open file: '" + keyStorePath + "' failed"); + return RET_FAILED; + } + + p12 = d2i_PKCS12_bio(bioOut, NULL); + if (Pkcs12PasswordParse(p12, keyStorePwd, keyStorePath) == RET_FAILED) { + KeyPairFree(cert, p12, bioOut, ""); + SetPassWordStatus(false); + return RET_FAILED; + } + int status = FindKeyPair(p12, alias, keyPwd, keyStorePwd, evpPkey, keyStorePath); + if (status == RET_FAILED) { + KeyPairFree(cert, p12, bioOut, ""); + return RET_FAILED; + } + + KeyPairFree(cert, p12, bioOut, ""); + return RET_OK; +} + +int KeyStoreHelper::Pkcs12PasswordParse(PKCS12* p12, const char* keyStorePwd, const std::string& keyStoreFile) +{ + if (p12 == NULL) { + PrintErrorNumberMsg("KEYSTORE_STRUCTURE_ERROR", KEYSTORE_STRUCTURE_ERROR, "'" + keyStoreFile + + "' keystore is not a PKCS12 structure"); + return RET_FAILED; + } + + if (keyStorePwd == NULL || *keyStorePwd == '\0') { + if (!PKCS12_mac_present(p12) || PKCS12_verify_mac(p12, NULL, 0)) { + keyStorePwd = NULL; + } else if (PKCS12_verify_mac(p12, "", 0)) { + keyStorePwd = ""; + } else { + goto err; + } + } else if (!PKCS12_verify_mac(p12, keyStorePwd, -1)) { + goto err; + } + + return RET_OK; +err: + PrintErrorNumberMsg("KEYSTORE_PASSWORD_ERROR", KEYSTORE_PASSWORD_ERROR, "keyStore password error"); + return RET_FAILED; +} + +bool KeyStoreHelper::IsKeyStoreFileExist(std::string& keyStorePath) +{ + if (keyStorePath.empty()) { + return false; + } + BIO* bioOut = nullptr; + bioOut = BIO_new_file(keyStorePath.c_str(), "rb"); + if (bioOut == nullptr) { + return false; + } + BIO_free(bioOut); + return true; +} + +EVP_PKEY* KeyStoreHelper::GenerateKeyPair(const std::string& algorithm, int keySize) +{ + if (algorithm.empty() || (0 == keySize)) { + SIGNATURE_TOOLS_LOGI("keyAlg and keySize is nullptr!"); + return nullptr; + } + EC_GROUP* group = nullptr; + EC_KEY* keyPair = EC_KEY_new(); + + if (keySize == static_cast(NIST_P_256)) { + group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); + } else if (keySize == static_cast(NIST_P_384)) { + group = EC_GROUP_new_by_curve_name(NID_secp384r1); + } else { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + KeyPairFree(group, keyPair, "Algorithm length error"); + return nullptr; + } + if (!group) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + KeyPairFree(group, keyPair, "Elliptic curve encryption using P256 or P384 failed"); + return nullptr; + } + + EC_KEY_set_group(keyPair, group); + if (EC_KEY_generate_key(keyPair) != 1) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + KeyPairFree(group, keyPair, "Description Failed to generate an elliptic curve key pair"); + return nullptr; + } + if (EC_KEY_check_key(keyPair) != 1) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + KeyPairFree(group, keyPair, "Description Failed to generate an elliptic curve key pair"); + return nullptr; + } + EVP_PKEY* pkey = EVP_PKEY_new(); + EVP_PKEY_set1_EC_KEY(pkey, keyPair); + KeyPairFree(group, keyPair, ""); + return pkey; +} + +PKCS12* KeyStoreHelper::CreatePKCS12(const char* keyStorePwd, const char* keyPwd, const char* name, EVP_PKEY* pkey, + X509* cert, int keyNid, int certNid, int iter, + int macStatus, int keyType, STACK_OF(PKCS7)** safes) +{ + PKCS12* p12 = NULL; + STACK_OF(PKCS12_SAFEBAG)* bags = NULL; + unsigned char keyId[EVP_MAX_MD_SIZE]; + unsigned int keyIdLen = 0; + PKCS12_SAFEBAG* bag = NULL; + + if (!certNid) { + certNid = NID_PBE_CBC; + } + SetNidMac(keyNid, iter, macStatus); + if (!pkey && !cert) { + PKCS12err(PKCS12_F_PKCS12_CREATE, PKCS12_R_INVALID_NULL_ARGUMENT); + return NULL; + } + + if (!X509_check_private_key(cert, pkey)) { + return NULL; + } + X509_digest(cert, EVP_sha384(), keyId, &keyIdLen); + + if (SetCertPkcs12(cert, bag, bags, keyId, keyIdLen, name, safes, certNid, iter, keyStorePwd) == RET_FAILED) { + goto err; + } + + if (SetPkeyPkcs12(pkey, bag, bags, name, safes, iter, keyPwd, keyType, keyNid, keyId, keyIdLen) == RET_FAILED) { + goto err; + } + + p12 = PKCS12_add_safes(*safes, 0); + + if (!p12) { + goto err; + } + safes = NULL; + if ((macStatus != -1) && !PKCS12_set_mac(p12, keyStorePwd, -1, NULL, 0, macStatus, NULL)) { + goto err; + } + return p12; + +err: + sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); + return NULL; +} + +void KeyStoreHelper::SetNidMac(int& nidKey, int& iter, int& macStatus) +{ + if (!nidKey) { + nidKey = NID_TRIPLEDES_CBC; + } + + if (!iter) { + iter = PKCS12_DEFAULT_ITER; + } + + if (!macStatus) { + macStatus = 1; + } +} + +int KeyStoreHelper::SetCertPkcs12(X509* cert, PKCS12_SAFEBAG* bag, STACK_OF(PKCS12_SAFEBAG)* certBags, + unsigned char* keyId, unsigned int keyIdLen, + const char* name, STACK_OF(PKCS7)** safes, + int certNid, int iter, const char* keyStorePwd) +{ + if (cert) { + bag = PKCS12_add_cert(&certBags, cert); + if (name && !PKCS12_add_friendlyname(bag, name, -1)) { + goto err; + } + + if (keyIdLen && !PKCS12_add_localkeyid(bag, keyId, keyIdLen)) { + goto err; + } + } + + if (certBags && !PKCS12_add_safe(safes, certBags, certNid, iter, keyStorePwd)) { + goto err; + } + + sk_PKCS12_SAFEBAG_pop_free(certBags, PKCS12_SAFEBAG_free); + certBags = nullptr; + return RET_OK; +err: + sk_PKCS12_SAFEBAG_pop_free(certBags, PKCS12_SAFEBAG_free); + certBags = nullptr; + return RET_FAILED; +} + +int KeyStoreHelper::SetPkeyPkcs12(EVP_PKEY* pkey, PKCS12_SAFEBAG* bag, STACK_OF(PKCS12_SAFEBAG)* keyBags, + const char* name, STACK_OF(PKCS7)** safes, int iter, const char* keyPwd, + int keyType, int keyNid, unsigned char* keyId, unsigned int keyIdLen) +{ + if (pkey) { + bag = PKCS12_add_key(&keyBags, pkey, keyType, iter, keyNid, keyPwd); + if (!bag) { + return RET_FAILED; + } + + if (GetAttrNid(bag, pkey, NID_ms_csp_name) == RET_FAILED) { + goto err; + } + + if (GetAttrNid(bag, pkey, NID_LocalKeySet) == RET_FAILED) { + goto err; + } + + if (name && !PKCS12_add_friendlyname(bag, name, -1)) { + goto err; + } + + if (keyIdLen && !PKCS12_add_localkeyid(bag, keyId, keyIdLen)) { + goto err; + } + } + if (keyBags && !PKCS12_add_safe(safes, keyBags, -1, 0, NULL)) { + goto err; + } + + sk_PKCS12_SAFEBAG_pop_free(keyBags, PKCS12_SAFEBAG_free); + keyBags = nullptr; + return RET_OK; +err: + sk_PKCS12_SAFEBAG_pop_free(keyBags, PKCS12_SAFEBAG_free); + keyBags = nullptr; + return RET_FAILED; +} + +int KeyStoreHelper::GetAttrNid(PKCS12_SAFEBAG* bag, EVP_PKEY* pkey, int nid) +{ + int idx; + X509_ATTRIBUTE* attr; + idx = EVP_PKEY_get_attr_by_NID(pkey, nid, -1); + if (idx < 0) { + return RET_OK; + } + attr = EVP_PKEY_get_attr(pkey, idx); + STACK_OF(X509_ATTRIBUTE)* attrlib = const_cast(PKCS12_SAFEBAG_get0_attrs(bag)); + if (!X509at_add1_attr(&attrlib, attr)) { + return RET_FAILED; + } + return RET_OK; +} + +int KeyStoreHelper::ParsePkcs12Safebag(PKCS12_SAFEBAG* bag, const char* pass, int passlen, STACK_OF(X509)* ocerts) +{ + X509* x509Cert = nullptr; + const ASN1_TYPE* attr; + ASN1_BMPSTRING* name = NULL; + ASN1_OCTET_STRING* kid = NULL; + if ((attr = PKCS12_SAFEBAG_get0_attr(bag, NID_friendlyName))) { + name = attr->value.bmpstring; + } + + if ((attr = PKCS12_SAFEBAG_get0_attr(bag, NID_localKeyID))) { + kid = attr->value.octet_string; + } + + if (PKCS12_SAFEBAG_get_nid(bag) != NID_certBag && PKCS12_SAFEBAG_get_bag_nid(bag) != NID_x509Certificate) { + return RET_OK; + } + + if ((x509Cert = PKCS12_SAFEBAG_get1_cert(bag)) == NULL) { + return RET_FAILED; + } + + if (kid && !X509_keyid_set1(x509Cert, kid->data, kid->length)) { + goto err; + } + + if (name) { + int len; + unsigned char* data; + len = ASN1_STRING_to_UTF8(&data, name); + if (!SetX509Alias(len, x509Cert, data)) { + goto err; + } + } + if (!sk_X509_push(ocerts, x509Cert)) { + goto err; + } + + return RET_OK; +err: + X509_free(x509Cert); + return RET_FAILED; +} + +bool KeyStoreHelper::SetX509Alias(int len, X509* x509, unsigned char* data) +{ + if (len >= 0) { + int r = X509_alias_set1(x509, data, len); + OPENSSL_free(data); + if (!r) { + X509_free(x509); + return false; + } + } + return true; +} + +int KeyStoreHelper::ParsePkcs12Safebags(const STACK_OF(PKCS12_SAFEBAG)* bags, const char* pass, + int passlen, STACK_OF(X509)* ocerts) +{ + int i; + for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) { + if (ParsePkcs12Safebag(sk_PKCS12_SAFEBAG_value(bags, i), pass, passlen, ocerts) == RET_FAILED) + return RET_FAILED; + } + return RET_OK; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/utils/src/string_utils.cpp b/binary_sign_tool/utils/src/string_utils.cpp new file mode 100644 index 00000000..c7be15f6 --- /dev/null +++ b/binary_sign_tool/utils/src/string_utils.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "string_utils.h" +#include +#include + +#include "securec.h" + +namespace OHOS { +namespace SignatureTools { + +bool StringUtils::IsEmpty(const std::string& cs) +{ + return cs.empty(); +} + +bool StringUtils::ContainsCase(const std::vector &strs, const std::string& str) +{ + std::string fileSuffix = str; + std::transform(fileSuffix.begin(), fileSuffix.end(), fileSuffix.begin(), + [](unsigned char c) { return std::tolower(c); }); + return std::any_of(strs.begin(), strs.end(), [&fileSuffix](const std::string& val) {return val == fileSuffix; }); +} + +bool StringUtils::CaseCompare(const std::string& str1, const std::string& str2) +{ + return str1 == str2; +} +std::vector StringUtils::SplitString(const std::string& str, char delimiter) +{ + std::vector tokens; + std::istringstream tokenStream(str); + std::string token; + while (std::getline(tokenStream, token, delimiter)) { + tokens.push_back(token); + } + return tokens; +} +std::string StringUtils::Trim(const std::string& str) +{ + size_t startpos = str.find_first_not_of(" \n\r\f\v"); + if (std::string::npos == startpos) { + return ""; + } + size_t endpos = str.find_last_not_of(" \n\r\f\v"); + return str.substr(startpos, endpos - startpos + 1); +} +std::string StringUtils::FormatLoading(std::string& dealStr) +{ + char comma = ','; + char slash = '/'; + std::string del = dealStr.substr(dealStr.find_first_of("/") + 1, dealStr.size()); + int position = 0; + while ((position = del.find(slash, position)) != std::string::npos) { + del.insert(position + 1, " "); + position++; + } + std::replace(del.begin(), del.end(), slash, comma); + return del.append("\n"); +} +std::string StringUtils::Pkcs7ToString(PKCS7* p7) +{ + unsigned char* out = NULL; + int outSize = i2d_PKCS7(p7, &out); + if (out == NULL || outSize <= 0) { + SIGNATURE_TOOLS_LOGE("pkcs7 to string failed"); + return ""; + } + std::string ret; + ret.clear(); + ret.resize(outSize); + std::copy(out, out + outSize, &ret[0]); + OPENSSL_free(out); + return ret; +} +std::string StringUtils::x509CertToString(X509* cert) +{ + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + BIO* bio = BIO_new(BIO_s_mem()); + PEM_write_bio_X509(bio, cert); + char* buffer; + long length = BIO_get_mem_data(bio, &buffer); + std::string certStr(buffer, length); + BIO_free(bio); + return certStr; +} +std::string StringUtils::SubjectToString(X509* cert) +{ + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + X509_NAME* subjectName = X509_get_subject_name(cert); + if (!subjectName) { + SIGNATURE_TOOLS_LOGE("Error getting subject name"); + return ""; + } + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + char* subjectStr = X509_NAME_oneline(subjectName, NULL, 0); + if (!subjectStr) { + SIGNATURE_TOOLS_LOGE("Error create subject string"); + return ""; + } + std::string subjectString(subjectStr); + std::string result = FormatLoading(subjectString); + OPENSSL_free(subjectStr); + return result; +} +bool StringUtils::CheckStringToint(const std::string& in, int& out) +{ + std::istringstream iss(in); + if ((iss >> out) && iss.eof()) { + return true; + } + SIGNATURE_TOOLS_LOGE("Cannot convert string:%s to integer", in.c_str()); + return false; +} +} // namespace SignatureTools +} // namespace OHOS diff --git a/binary_sign_tool/utils/src/verify_cert_openssl_utils.cpp b/binary_sign_tool/utils/src/verify_cert_openssl_utils.cpp new file mode 100644 index 00000000..34923cf3 --- /dev/null +++ b/binary_sign_tool/utils/src/verify_cert_openssl_utils.cpp @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "verify_cert_openssl_utils.h" +#include +#include +#include + +#include "openssl/pem.h" +#include "openssl/sha.h" +#include "signature_tools_log.h" +#include "securec.h" +#include "verify_hap_openssl_utils.h" + +namespace OHOS { +namespace SignatureTools { + +const uint32_t VerifyCertOpensslUtils::MIN_CERT_CHAIN_LEN_NEED_VERIFY_CRL = 2; +const int32_t VerifyCertOpensslUtils::OPENSSL_READ_CRL_MAX_TIME = 1048576; // 1024 * 1024 +const int32_t VerifyCertOpensslUtils::OPENSSL_READ_CRL_LEN_EACH_TIME = 1024; +const int32_t VerifyCertOpensslUtils::BASE64_ENCODE_LEN_OF_EACH_GROUP_DATA = 4; +const int32_t VerifyCertOpensslUtils::BASE64_ENCODE_PACKET_LEN = 3; + +void VerifyCertOpensslUtils::GenerateCertSignFromCertStack(STACK_OF(X509)* stackCerts, CertSign& certVisitSign) +{ + if (stackCerts == nullptr) { + return; + } + for (int32_t i = 0; i < sk_X509_num(stackCerts); i++) { + X509* x509Cert = sk_X509_value(stackCerts, i); + if (x509Cert == nullptr) { + continue; + } + certVisitSign[x509Cert] = false; + } +} + +void VerifyCertOpensslUtils::ClearCertVisitSign(CertSign& certVisitSign) +{ + for (auto& certPair : certVisitSign) { + certPair.second = false; + } +} + +bool VerifyCertOpensslUtils::GetCertsChain(CertChain& certsChain, CertSign& certVisitSign) +{ + if (certsChain.empty() || certVisitSign.empty()) { + SIGNATURE_TOOLS_LOGE("input is invalid"); + return false; + } + X509* issuerCert; + X509* cert = certsChain[0]; + while ((issuerCert = FindCertOfIssuer(cert, certVisitSign)) != nullptr) { + certsChain.push_back(X509_dup(issuerCert)); + certVisitSign[issuerCert] = true; + cert = issuerCert; + } + if (CertVerify(cert, cert) == false) { + SIGNATURE_TOOLS_LOGE("CertVerify is invalid"); + return false; + } + { + X509_NAME* aName = X509_get_issuer_name(cert); + X509_NAME* bName = X509_get_subject_name(cert); + if (aName == NULL || bName == NULL) { + SIGNATURE_TOOLS_LOGE("NULL X509_NAME"); + return false; + } + if (X509_NAME_cmp(aName, bName) != 0) { + SIGNATURE_TOOLS_LOGE("compare error!"); + return false; + } + return true; + } +} + +X509* VerifyCertOpensslUtils::FindCertOfIssuer(X509* cert, CertSign& certVisitSign) +{ + if (cert == nullptr) { + SIGNATURE_TOOLS_LOGE("input is invalid"); + return nullptr; + } + X509_NAME* signCertIssuerName = X509_get_issuer_name(cert); + for (auto certPair : certVisitSign) { + if (certPair.second) { + continue; + } + X509* issuerCert = certPair.first; + X509_NAME* issuerCertSubjectName = X509_get_subject_name(issuerCert); + /* verify sign and issuer */ + if (X509NameCompare(issuerCertSubjectName, signCertIssuerName) && + CertVerify(cert, issuerCert)) { + return issuerCert; + } + } + return nullptr; +} + +bool VerifyCertOpensslUtils::CertVerify(X509* cert, const X509* issuerCert) +{ + if (cert == nullptr) { + SIGNATURE_TOOLS_LOGE("input is invalid"); + return false; + } + EVP_PKEY* caPublicKey = X509_get0_pubkey(issuerCert); + if (caPublicKey == nullptr) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("get pubkey from caCert failed"); + return false; + } + return X509_verify(cert, caPublicKey) > 0; +} + +bool VerifyCertOpensslUtils::VerifyCertChainPeriodOfValidity(CertChain& certsChain, + const ASN1_TYPE* signTime) +{ + if (certsChain.empty()) { + return false; + } + for (uint32_t i = 0; i < certsChain.size() - 1; i++) { + if (certsChain[i] == nullptr) { + SIGNATURE_TOOLS_LOGE("%dst cert is nullptr", i); + return false; + } + const ASN1_TIME* notBefore = X509_get0_notBefore(certsChain[i]); + const ASN1_TIME* notAfter = X509_get0_notAfter(certsChain[i]); + if (!CheckSignTimeInValidPeriod(signTime, notBefore, notAfter)) { + SIGNATURE_TOOLS_LOGE("%dst cert is not in period of validity", i); + return false; + } + } + return true; +} + +bool VerifyCertOpensslUtils::CheckAsn1TimeIsValid(const ASN1_TIME* asn1Time) +{ + if (asn1Time == nullptr || asn1Time->data == nullptr) { + return false; + } + return true; +} + +bool VerifyCertOpensslUtils::CheckAsn1TypeIsValid(const ASN1_TYPE* asn1Type) +{ + if (asn1Type == nullptr || asn1Type->value.asn1_string == nullptr || + asn1Type->value.asn1_string->data == nullptr) { + return false; + } + return true; +} + +bool VerifyCertOpensslUtils::CheckSignTimeInValidPeriod(const ASN1_TYPE* signTime, + const ASN1_TIME* notBefore, + const ASN1_TIME* notAfter) +{ + if (!CheckAsn1TimeIsValid(notBefore) || !CheckAsn1TimeIsValid(notAfter)) { + SIGNATURE_TOOLS_LOGE("no valid period"); + return false; + } + if (!CheckAsn1TypeIsValid(signTime)) { + SIGNATURE_TOOLS_LOGE("signTime is invalid"); + return false; + } + if (ASN1_TIME_compare(notBefore, signTime->value.asn1_string) > 0 || + ASN1_TIME_compare(notAfter, signTime->value.asn1_string) < 0) { + SIGNATURE_TOOLS_LOGE("Out of valid period, signTime: %s, " + "notBefore:%s, notAfter : %s", + signTime->value.asn1_string->data, notBefore->data, notAfter->data); + return false; + } + SIGNATURE_TOOLS_LOGD("signTime type: %d, data: %s, " + "notBefore:%s, notAfter : %s", + signTime->type, signTime->value.asn1_string->data, + notBefore->data, notAfter->data); + return true; +} + +bool VerifyCertOpensslUtils::VerifyCrl(CertChain& certsChain, STACK_OF(X509_CRL)* crls, + Pkcs7Context& pkcs7Context) +{ + if (certsChain.empty()) { + SIGNATURE_TOOLS_LOGE("cert chain is null"); + return false; + } + /* get signed cert's issuer and then it will be used to find local crl */ + if (!GetIssuerFromX509(certsChain[0], pkcs7Context.certIssuer)) { + SIGNATURE_TOOLS_LOGE("get issuer of signed cert failed"); + return false; + } + X509_CRL* targetCrl = GetCrlBySignedCertIssuer(crls, certsChain[0]); + /* crl is optional */ + if (targetCrl != nullptr && certsChain.size() >= MIN_CERT_CHAIN_LEN_NEED_VERIFY_CRL) { + /* if it include crl, it must be verified by ca cert */ + if (X509_CRL_verify(targetCrl, X509_get0_pubkey(certsChain[1])) <= 0) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("verify crlInPackage failed"); + return false; + } + } + return true; +} + +X509_CRL* VerifyCertOpensslUtils::GetCrlBySignedCertIssuer(STACK_OF(X509_CRL)* crls, const X509* cert) +{ + if (crls == nullptr || cert == nullptr) { + return nullptr; + } + X509_NAME* certIssuerName = X509_get_issuer_name(cert); + for (int32_t i = 0; i < sk_X509_CRL_num(crls); i++) { + X509_CRL* x509Crl = sk_X509_CRL_value(crls, i); + if (x509Crl == nullptr) { + continue; + } + X509_NAME* crlIssuer = X509_CRL_get_issuer(x509Crl); + if (X509NameCompare(crlIssuer, certIssuerName)) { + return x509Crl; + } + } + return nullptr; +} + +bool VerifyCertOpensslUtils::X509NameCompare(const X509_NAME* a, const X509_NAME* b) +{ + if (a == nullptr || b == nullptr) { + return false; + } + return X509_NAME_cmp(a, b) == 0; +} + +bool VerifyCertOpensslUtils::GetSubjectFromX509(const X509* cert, std::string& subject) +{ + if (cert == nullptr) { + SIGNATURE_TOOLS_LOGE("cert is nullptr"); + return false; + } + X509_NAME* name = X509_get_subject_name(cert); + subject = GetDnToString(name); + SIGNATURE_TOOLS_LOGD("subject = %s", subject.c_str()); + return true; +} + +bool VerifyCertOpensslUtils::GetIssuerFromX509(const X509* cert, std::string& issuer) +{ + if (cert == nullptr) { + SIGNATURE_TOOLS_LOGE("cert is nullptr"); + return false; + } + X509_NAME* name = X509_get_issuer_name(cert); + issuer = GetDnToString(name); + SIGNATURE_TOOLS_LOGD("cert issuer = %s", issuer.c_str()); + return true; +} + +std::string VerifyCertOpensslUtils::GetDnToString(X509_NAME* x509Name) +{ + if (x509Name == nullptr) { + return ""; + } + std::string countryNameString; + GetTextFromX509Name(x509Name, NID_countryName, countryNameString); + std::string organizationName; + GetTextFromX509Name(x509Name, NID_organizationName, organizationName); + std::string organizationalUnitName; + GetTextFromX509Name(x509Name, NID_organizationalUnitName, organizationalUnitName); + std::string commonName; + GetTextFromX509Name(x509Name, NID_commonName, commonName); + return "C=" + countryNameString + ", O=" + organizationName + ", OU=" + organizationalUnitName + + ", CN=" + commonName; +} + +void VerifyCertOpensslUtils::GetTextFromX509Name(X509_NAME* name, int32_t nId, std::string& text) +{ + int32_t textLen = X509_NAME_get_text_by_NID(name, nId, nullptr, 0); + if (textLen <= 0) { + return; + } + std::unique_ptr buffer = std::make_unique(textLen + 1); + if (X509_NAME_get_text_by_NID(name, nId, buffer.get(), textLen + 1) != textLen) { + return; + } + text = std::string(buffer.get()); +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/binary_sign_tool/utils/src/verify_hap_openssl_utils.cpp b/binary_sign_tool/utils/src/verify_hap_openssl_utils.cpp new file mode 100644 index 00000000..06c80669 --- /dev/null +++ b/binary_sign_tool/utils/src/verify_hap_openssl_utils.cpp @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2025-2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "verify_hap_openssl_utils.h" +#include "signature_tools_log.h" +#include "openssl/asn1.h" +#include "openssl/bio.h" +#include "openssl/crypto.h" +#include "openssl/err.h" +#include "openssl/obj_mac.h" +#include "openssl/objects.h" +#include "openssl/rsa.h" +#include "openssl/x509.h" +#include "openssl/pem.h" +#include "constant.h" + +namespace OHOS { +namespace SignatureTools { +using Pkcs7SignerInfoStack = STACK_OF(PKCS7_SIGNER_INFO); +using X509AttributeStack = STACK_OF(X509_ATTRIBUTE); +const int32_t VerifyHapOpensslUtils::OPENSSL_PKCS7_VERIFY_SUCCESS = 1; +const int32_t VerifyHapOpensslUtils::OPENSSL_ERR_MESSAGE_MAX_LEN = 1024; +/* +* OPENSSL_READ_DATA_MAX_TIME * OPENSSL_READ_DATA_LEN_EACH_TIME < 2GBytes. +* make the maximum size of data that can be read each time be 1 KBytes, +* so the maximum times of read data is 1024 * 1024 * 2 = 2097152; +*/ +const int32_t VerifyHapOpensslUtils::OPENSSL_READ_DATA_MAX_TIME = 2097152; +const int32_t VerifyHapOpensslUtils::OPENSSL_READ_DATA_LEN_EACH_TIME = 1024; +/* Signature algorithm OID for extended PKCS7 */ +const std::string VerifyHapOpensslUtils::PKCS7_EXT_SHAWITHRSA_PSS = PKCS7_EXT_SIGNATURE_OID; +const int32_t VerifyHapOpensslUtils::MAX_OID_LENGTH = 128; + +bool VerifyHapOpensslUtils::ParsePkcs7Package(const unsigned char packageData[], + uint32_t packageLen, Pkcs7Context& pkcs7Context) +{ + if (packageData == nullptr || packageLen == 0) { + SIGNATURE_TOOLS_LOGE("invalid input"); + return false; + } + pkcs7Context.p7 = d2i_PKCS7(nullptr, &packageData, packageLen); + if (!CheckPkcs7SignedDataIsValid(pkcs7Context.p7)) { + GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("p7 is invalid"); + return false; + } + if (!GetContentInfo(pkcs7Context.p7->d.sign->contents, pkcs7Context.content)) { + SIGNATURE_TOOLS_LOGE("Get content from pkcs7 failed"); + return false; + } + return true; +} + +bool VerifyHapOpensslUtils::GetCertChains(PKCS7* p7, Pkcs7Context& pkcs7Context) +{ + if (!CheckPkcs7SignedDataIsValid(p7)) { + SIGNATURE_TOOLS_LOGE("p7 is invalid"); + return false; + } + CertSign certVisitSign; + VerifyCertOpensslUtils::GenerateCertSignFromCertStack(p7->d.sign->cert, certVisitSign); + Pkcs7SignerInfoStack* signerInfoStack = PKCS7_get_signer_info(p7); + if (signerInfoStack == nullptr) { + SIGNATURE_TOOLS_LOGE("get signerInfoStack error"); + GetOpensslErrorMessage(); + return false; + } + int32_t signCount = sk_PKCS7_SIGNER_INFO_num(signerInfoStack); + if (signCount <= 0) { + SIGNATURE_TOOLS_LOGE("can not find signinfo"); + return false; + } + for (int32_t i = 0; i < signCount; i++) { + /* get ith signInfo */ + PKCS7_SIGNER_INFO* signInfo = sk_PKCS7_SIGNER_INFO_value(signerInfoStack, i); + if (signInfo == nullptr) { + SIGNATURE_TOOLS_LOGE("signInfo %dst is nullptr", i); + return false; + } + /* GET X509 certificate */ + X509* cert = PKCS7_cert_from_signer_info(p7, signInfo); + if (cert == nullptr) { + SIGNATURE_TOOLS_LOGE("get cert for %dst signInfo failed", i); + return false; + } + CertChain certChain; + pkcs7Context.certChain.push_back(certChain); + pkcs7Context.certChain[i].push_back(X509_dup(cert)); + VerifyCertOpensslUtils::ClearCertVisitSign(certVisitSign); + certVisitSign[cert] = true; + if (!VerifyCertChain(pkcs7Context.certChain[i], p7, signInfo, pkcs7Context, certVisitSign)) { + SIGNATURE_TOOLS_LOGE("verify %dst certchain failed", i); + return false; + } + } + return true; +} + +bool VerifyHapOpensslUtils::VerifyCertChain(CertChain& certsChain, PKCS7* p7, + PKCS7_SIGNER_INFO* signInfo, + Pkcs7Context& pkcs7Context, + CertSign& certVisitSign) +{ + if (!VerifyCertOpensslUtils::GetCertsChain(certsChain, certVisitSign)) { + SIGNATURE_TOOLS_LOGE("get cert chain for signInfo failed"); + return false; + } + ASN1_TYPE* signTime = PKCS7_get_signed_attribute(signInfo, NID_pkcs9_signingTime); + if (!VerifyCertOpensslUtils::VerifyCertChainPeriodOfValidity(certsChain, signTime)) { + SIGNATURE_TOOLS_LOGE("VerifyCertChainPeriodOfValidity for signInfo failed"); + return false; + } + return true; +} + +bool VerifyHapOpensslUtils::CheckPkcs7SignedDataIsValid(const PKCS7* p7) +{ + if (p7 == nullptr || !PKCS7_type_is_signed(p7) || p7->d.sign == nullptr) { + return false; + } + return true; +} + +bool VerifyHapOpensslUtils::GetCrlStack(PKCS7* p7, STACK_OF(X509_CRL)* x509Crl) +{ + if (!CheckPkcs7SignedDataIsValid(p7)) { + return false; + } + x509Crl = p7->d.sign->crl; + return true; +} + +bool VerifyHapOpensslUtils::VerifyPkcs7(Pkcs7Context& pkcs7Context) +{ + if (!CheckPkcs7SignedDataIsValid(pkcs7Context.p7)) { + SIGNATURE_TOOLS_LOGE("p7 type is invalid signed_data_pkcs7"); + return false; + } + if (!VerifyPkcs7SignedData(pkcs7Context)) { + SIGNATURE_TOOLS_LOGE("verify p7 error"); + return false; + } + return true; +} + +bool VerifyHapOpensslUtils::VerifyPkcs7SignedData(Pkcs7Context& pkcs7Context) +{ + /* get signed data which was used to be signed */ + BIO* p7Bio = PKCS7_dataDecode(pkcs7Context.p7, nullptr, nullptr, nullptr); + if (p7Bio == nullptr) { + SIGNATURE_TOOLS_LOGE("get p7bio error"); + GetOpensslErrorMessage(); + return false; + } + char buf[OPENSSL_READ_DATA_LEN_EACH_TIME] = { 0 }; + int32_t readLen = BIO_read(p7Bio, buf, sizeof(buf)); + int32_t readTime = 0; + while ((readLen > 0) && (++readTime < OPENSSL_READ_DATA_MAX_TIME)) { + readLen = BIO_read(p7Bio, buf, sizeof(buf)); + } + Pkcs7SignerInfoStack* signerInfoStack = PKCS7_get_signer_info(pkcs7Context.p7); + if (signerInfoStack == nullptr) { + SIGNATURE_TOOLS_LOGE("get signerInfoStack error"); + BIO_free_all(p7Bio); + GetOpensslErrorMessage(); + return false; + } + /* get the num of signInfo */ + int32_t signCount = sk_PKCS7_SIGNER_INFO_num(signerInfoStack); + if (signCount <= 0) { + SIGNATURE_TOOLS_LOGE("can not find signinfo"); + BIO_free_all(p7Bio); + return false; + } + for (int32_t i = 0; i < signCount; i++) { + if (!VerifySignInfo(signerInfoStack, p7Bio, i, pkcs7Context)) { + SIGNATURE_TOOLS_LOGE("Verify %dst signInfo failed", i); + BIO_free_all(p7Bio); + return false; + } + } + BIO_free_all(p7Bio); + return true; +} + +bool VerifyHapOpensslUtils::VerifySignInfo(STACK_OF(PKCS7_SIGNER_INFO)* signerInfoStack, + BIO* p7Bio, int32_t signInfoNum, Pkcs7Context& pkcs7Context) +{ + if (signerInfoStack == nullptr || p7Bio == nullptr) { + SIGNATURE_TOOLS_LOGE("invalid input"); + return false; + } + /* get signInfo */ + PKCS7_SIGNER_INFO* signInfo = sk_PKCS7_SIGNER_INFO_value(signerInfoStack, signInfoNum); + if (signInfo == nullptr) { + SIGNATURE_TOOLS_LOGE("signInfo %dst is nullptr", signInfoNum); + return false; + } + /* GET X509 certificate */ + X509* cert = pkcs7Context.certChain[signInfoNum][0]; + + if (PKCS7_signatureVerify(p7Bio, pkcs7Context.p7, signInfo, cert) <= 0) { + SIGNATURE_TOOLS_LOGE("PKCS7_signatureVerify %dst signInfo failed", signInfoNum); + GetOpensslErrorMessage(); + return false; + } + + return true; +} + +bool VerifyHapOpensslUtils::GetContentInfo(const PKCS7* p7ContentInfo, ByteBuffer& content) +{ + if ((p7ContentInfo == nullptr) || !PKCS7_type_is_data(p7ContentInfo)) { + SIGNATURE_TOOLS_LOGE("p7ContentInfo is invalid"); + return false; + } + ASN1_OCTET_STRING* strContentInfo = p7ContentInfo->d.data; + if (strContentInfo == nullptr) { + SIGNATURE_TOOLS_LOGE("strContentInfo is invalid"); + return false; + } + int32_t strContentInfoLen = strContentInfo->length; + unsigned char* strContentInfoData = strContentInfo->data; + if (strContentInfoData == nullptr || strContentInfoLen <= 0) { + SIGNATURE_TOOLS_LOGE("ASN1_OCTET_STRING is invalid"); + return false; + } + content.SetCapacity(strContentInfoLen); + content.PutData(0, reinterpret_cast(strContentInfoData), strContentInfoLen); + SIGNATURE_TOOLS_LOGD("strContentInfoLen: %d", strContentInfoLen); + return true; +} + +void VerifyHapOpensslUtils::GetOpensslErrorMessage() +{ + unsigned long retOpenssl; + char errOpenssl[OPENSSL_ERR_MESSAGE_MAX_LEN]; + while ((retOpenssl = ERR_get_error()) != 0) { + ERR_error_string(retOpenssl, errOpenssl); + SIGNATURE_TOOLS_LOGE("openssl err: %lu, message: %s", retOpenssl, errOpenssl); + } +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/bundle.json b/hapsigntool_cpp/bundle.json index 75f884b9..ee3d393c 100644 --- a/hapsigntool_cpp/bundle.json +++ b/hapsigntool_cpp/bundle.json @@ -31,11 +31,13 @@ "ram": "0KB", "deps": { "components": [ + "bounds_checking_function", "c_utils", "json", "zlib" ], "third_party": [ + "elfio", "bzip2", "openssl", "jsoncpp" @@ -43,6 +45,7 @@ }, "build": { "sub_component": [ + "//developtools/hapsigner/binary_sign_tool:binary-sign-tool", "//developtools/hapsigner/hapsigntool_cpp:hap-sign-tool" ], "inner_kits": [], -- Gitee