diff --git a/OAT.xml b/OAT.xml index b2fcfdde6d957f306ffc290e708fb65619e6d1fb..f8a62daa9ab34fd7cfd3a6b4f9e36d4d4cb886e9 100644 --- a/OAT.xml +++ b/OAT.xml @@ -31,9 +31,11 @@ - + + + @@ -42,13 +44,18 @@ - + + + + + + @@ -61,10 +68,12 @@ + - + + diff --git a/hapsigntool_cpp/BUILD.gn b/hapsigntool_cpp/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..b8be05beec614bd5c8debc4ec15ba4a5bcb69d3a --- /dev/null +++ b/hapsigntool_cpp/BUILD.gn @@ -0,0 +1,114 @@ +# Copyright (c) 2024-2024 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("zip/signature_tools_zip.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/localization_adapter.cpp", + "${signature_tools_api}/src/sign_tool_service_impl.cpp", + "${signature_tools_api}/src/cert_tools.cpp", + "${signature_tools_signer}/src/signer_factory.cpp", + "${signature_tools_signer}/src/local_signer.cpp", +] + +ohos_executable("hap-sign-tool") { + signature_tools_main_include += signature_tools_utils_include + signature_tools_main_include += signature_tools_zip_include + + # signature_tools_main_include += signature_tools_entity_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 + + # 在 //developtools/signaturetools/services/zip 模块里面定义编译脚本 signature_tools_zip.gni + signature_tools_main_src += signature_tools_zip_src + + # signature_tools_main_src += signature_tools_entity_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 + + defines = [ "SIGNATURE_LOG_DEBUG" ] + + deps = [ + "//third_party/bzip2:libbz2", + "//third_party/openssl:libcrypto_shared", + "//third_party/openssl:libssl_shared", + "//third_party/zlib:shared_libz", + ] + + external_deps = [ + "c_utils:utils", + "json:nlohmann_json_static", + ] + + cflags_cc = [ + "-std=c++17", + "-fno-rtti", + ] + + cflags = [ + "-fno-rtti", + "-Wno-c++20-extensions", + ] + + install_images = [ "system" ] + install_enable = true + part_name = "hapsigner" + subsystem_name = "developtools" +} diff --git a/hapsigntool_cpp/api/include/cert_tools.h b/hapsigntool_cpp/api/include/cert_tools.h new file mode 100644 index 0000000000000000000000000000000000000000..f95a6add846816673d51cad8bb3890ec18a2cefc --- /dev/null +++ b/hapsigntool_cpp/api/include/cert_tools.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024-2024 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_CERT_TOOLS_H +#define SIGNATRUETOOLS_CERT_TOOLS_H + +#include "cert_dn_utils.h" +#include "openssl/x509v3.h" +#include "openssl/rand.h" +#include "localization_adapter.h" +#include "securec.h" + +namespace OHOS { +namespace SignatureTools { + +class CertTools { +public: + static X509* GenerateRootCertificate(EVP_PKEY* keyPair, X509_REQ* certReq, Options* options); + static X509* GenerateSubCert(EVP_PKEY* keyPair, X509_REQ* certReq, Options* options); + static X509* GenerateCert(EVP_PKEY* keyPair, X509_REQ* certReq, Options* options); + static bool SaveCertTofile(const std::string& filename, X509* cert); + static X509_REQ* GenerateCsr(EVP_PKEY* evpPkey, std::string signAlgorithm, std::string subject); + static X509* SignCsrGenerateCert(X509_REQ* rootcsr, X509_REQ* subcsr, + EVP_PKEY* keyPair, Options* options); + static std::string CsrToString(X509_REQ* csr); + static X509* GenerateEndCert(X509_REQ* csr, EVP_PKEY* issuerKeyPair, + LocalizationAdapter& adapter, + const char signCapacity[], int capacityLen); + static X509* ReadfileToX509(const std::string& filename); + static bool SetBisicConstraints(Options* options, X509* cert); + static bool SetBisicConstraintsPathLen(Options* options, X509* cert); + static bool SetSubjectForCert(X509_REQ* certReq, X509* cert); + static bool SignForSubCert(X509* cert, X509_REQ* csr, X509_REQ* caReq, + EVP_PKEY* caPrikey, Options* options); + static bool SetKeyUsage(X509* cert, Options* options); + static bool SetkeyUsageExt(X509* cert, Options* options); + static bool SetCertValidity(X509* cert, int validity); + static bool SerialNumberBuilder(uint8_t* serialNum, int length); + static bool SetCertVersion(X509* cert, int versionNum); + static bool SetCertSerialNum(X509* cert); + static bool SetCertIssuerName(X509* cert, X509_NAME* issuer); + static bool SetCertSubjectName(X509* cert, X509_REQ* subjectCsr); + static bool SetCertValidityStartAndEnd(X509* cert, long vilidityStart, long vilidityEnd); + static bool SetCertPublickKey(X509* cert, X509_REQ* subjectCsr); + static bool SetBasicExt(X509* cert); + static bool SetkeyUsageExt(X509* cert); + static bool SetKeyUsageEndExt(X509* cert); + static bool SetKeyIdentifierExt(X509* cert); + static bool SetAuthorizeKeyIdentifierExt(X509* cert); + static bool SetSignCapacityExt(X509* cert, const char signCapacity[], int capacityLen); + static bool SignCert(X509* cert, EVP_PKEY* privateKey, std::string signAlg); + static bool SetExpandedInformation(X509* cert, Options* options); + static bool SetPubkeyAndSignCert(X509* cert, X509_REQ* issuercsr, + X509_REQ* certReq, EVP_PKEY* keyPair, Options* options); + CertTools() = default; + ~CertTools() = default; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_CERT_TOOLS_H diff --git a/hapsigntool_cpp/api/include/localization_adapter.h b/hapsigntool_cpp/api/include/localization_adapter.h new file mode 100644 index 0000000000000000000000000000000000000000..3a969685673ea20d9d72db5d26265d31294e18ae --- /dev/null +++ b/hapsigntool_cpp/api/include/localization_adapter.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2024-2024 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 "cert_dn_utils.h" +#include "signature_tools_log.h" +#include "verify_hap_openssl_utils.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* GetIssureKeyByAlias(); + 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/hapsigntool_cpp/api/include/service_api.h b/hapsigntool_cpp/api/include/service_api.h new file mode 100644 index 0000000000000000000000000000000000000000..968df287baec4243debdd77685da4c4383d2a455 --- /dev/null +++ b/hapsigntool_cpp/api/include/service_api.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024-2024 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 GenerateKeyStore(Options* params) = 0; + virtual bool GenerateCsr(Options* params) = 0; + virtual bool GenerateCert(Options* params) = 0; + virtual bool GenerateCA(Options* params) = 0; + virtual bool GenerateAppCert(Options* params) = 0; + virtual bool GenerateProfileCert(Options* params) = 0; + virtual bool SignProfile(Options* params) = 0; + virtual bool VerifyProfile(Options* params) = 0; + virtual bool SignHap(Options* params) = 0; + virtual bool VerifyHapSigner(Options* params) = 0; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNERTOOLS_SERVICE_API_H \ No newline at end of file diff --git a/hapsigntool_cpp/api/include/sign_tool_service_impl.h b/hapsigntool_cpp/api/include/sign_tool_service_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..878e566054668fb3cf72fa57dc23fa6684030c9f --- /dev/null +++ b/hapsigntool_cpp/api/include/sign_tool_service_impl.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024-2024 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 "cert_tools.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 GenerateCA(Options* options)override; + bool GenerateRootCertToFile(Options* options, EVP_PKEY* rootKey); + bool GenerateSubCertToFile(Options* options, EVP_PKEY* rootKey); + bool OutputModeOfCert(X509* cert, Options* options); + bool GenerateCert(Options* options)override; + bool GenerateKeyStore(Options* options)override; + bool GenerateCsr(Options* options)override; + bool OutputString(std::string content, std::string file); + bool GenerateAppCert(Options* option)override; + bool GenerateProfileCert(Options* options)override; + bool GetAndOutPutCert(LocalizationAdapter& adapter, X509* cert); + bool SignProfile(Options* options)override; + bool SignHap(Options* options)override; + bool VerifyProfile(Options* options)override; + bool OutPutCertChain(std::vector& certs, const std::string& outPutPath); + bool OutPutCert(X509* cert, const std::string& outPutPath); + bool PrintX509CertFromMemory(X509* cert); + bool PrintX509CertChainFromMemory(std::vector certs); + bool VerifyHapSigner(Options* option)override; + bool X509CertVerify(X509* cert, EVP_PKEY* privateKey); + X509_REQ* GetCsr(EVP_PKEY* keyPair, std::string signAlg, std::string subject); + int HandleIssuerKeyAliasEmpty(Options* options); + int HandleIsserKeyAliasNotEmpty(Options* options); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_SIGNTOOLSERVICELMPL_H diff --git a/hapsigntool_cpp/api/src/cert_tools.cpp b/hapsigntool_cpp/api/src/cert_tools.cpp new file mode 100644 index 0000000000000000000000000000000000000000..37826e945bafe816fc7caa4002d59ed89b9b3e2d --- /dev/null +++ b/hapsigntool_cpp/api/src/cert_tools.cpp @@ -0,0 +1,828 @@ +/* + * Copyright (c) 2024-2024 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 +#include + +#include "cert_tools.h" +#include "openssl/ec.h" +#include "openssl/obj_mac.h" +#include "openssl/asn1.h" +#include "signature_tools_log.h" +#include "constant.h" +#include "cmd_util.h" + +#define BASIC_NUMBER_TWO 2 + +namespace OHOS { +namespace SignatureTools { + +static std::unordered_map externDic{ + {"digitalSignature", X509v3_KU_DIGITAL_SIGNATURE}, + {"nonRepudiation", X509v3_KU_NON_REPUDIATION}, + {"keyEncipherment", X509v3_KU_KEY_ENCIPHERMENT}, + {"dataEncipherment", X509v3_KU_DATA_ENCIPHERMENT}, + {"keyAgreement", X509v3_KU_KEY_AGREEMENT}, + {"certificateSignature", X509v3_KU_KEY_CERT_SIGN}, + {"crlSignature", X509v3_KU_CRL_SIGN}, + {"encipherOnly", X509v3_KU_ENCIPHER_ONLY}, + {"decipherOnly", X509v3_KU_DECIPHER_ONLY}, + +}; + +static std::unordered_map externKey{ + {"serverAuthentication", "1.3.6.1.5.5.7.3.1"}, + {"clientAuthentication", "1.3.6.1.5.5.7.3.2"}, + {"codeSignature", "1.3.6.1.5.5.7.3.3"}, + {"emailProtection", "1.3.6.1.5.5.7.3.4"}, + {"smartCardLogin", "1.3.6.1.5.5.7.3.5"}, + {"timestamp", "1.3.6.1.5.5.7.3.8"}, + {"ocspSignature", "1.3.6.1.5.5.7.3.9"}, + +}; + +bool CertTools::SaveCertTofile(const std::string& filename, X509* cert) +{ + BIO* certBio = BIO_new_file(filename.data(), "w"); + if (!certBio) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("BIO_new failed"); + return false; + } + + if (PEM_write_bio_X509(certBio, cert) < 0) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("PEM_write_bio_X509 failed"); + BIO_free(certBio); + return false; + } + BIO_free(certBio); + return true; +} + +bool CertTools::SetBisicConstraints(Options* options, X509* cert) +{ + bool basicCon = options->GetBool(Options::BASIC_CONSTRAINTS); + if (basicCon) { + bool basicConstraintsCritical = options->GetBool(Options::BASIC_CONSTRAINTS_CRITICAL); + int critial = basicConstraintsCritical ? 1 : 0; + bool basicConstraintsCa = options->GetBool(Options::BASIC_CONSTRAINTS_CA); + std::string ContainCa = basicConstraintsCa ? "CA:TRUE" : "CA:FALSE"; + std::string constraints = ContainCa + "," + "pathlen:" + + std::to_string(options->GetInt(Options::BASIC_CONSTRAINTS_PATH_LEN)); + X509V3_CTX ctx; + X509V3_set_ctx_nodb(&ctx); + + X509_EXTENSION* ext = X509V3_EXT_conf_nid(NULL, &ctx, NID_basic_constraints, constraints.c_str()); + if (!X509_EXTENSION_set_critical(ext, critial)) { + SIGNATURE_TOOLS_LOGE("failed to set critical for extKeyUsage "); + X509_EXTENSION_free(ext); + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + return false; + } + if (!X509_add_ext(cert, ext, -1)) { + SIGNATURE_TOOLS_LOGE("X509_add_ext failed"); + X509_EXTENSION_free(ext); + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + return false; + } + X509_EXTENSION_free(ext); + } + + return true; +} + +bool CertTools::SetBisicConstraintsPathLen(Options* options, X509* cert) +{ + std::string setOptions = "CA:TRUE, pathlen:" + + std::to_string(options->GetInt(Options::BASIC_CONSTRAINTS_PATH_LEN)); + X509V3_CTX ctx; + X509V3_set_ctx_nodb(&ctx); + X509_EXTENSION* ext = X509V3_EXT_conf_nid(NULL, &ctx, NID_basic_constraints, setOptions.c_str()); + if (!X509_EXTENSION_set_critical(ext, 1)) { + SIGNATURE_TOOLS_LOGE("failed to set critical for extKeyUsage "); + X509_EXTENSION_free(ext); + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + return false; + } + if (!X509_add_ext(cert, ext, -1)) { + SIGNATURE_TOOLS_LOGE("X509_add_ext failed\n"); + X509_EXTENSION_free(ext); + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + return false; + } + X509_EXTENSION_free(ext); + return true; +} + +bool CertTools::SignForSubCert(X509* cert, X509_REQ* subcsr, X509_REQ* rootcsr, EVP_PKEY* caPrikey, Options* options) +{ + bool result = false; + std::string signAlg = options->GetString(Options::SIGN_ALG); + EVP_PKEY* pubKey = X509_REQ_get_pubkey(subcsr); + X509_NAME* issuerName = X509_REQ_get_subject_name(rootcsr); + X509_NAME* subjectName = X509_REQ_get_subject_name(subcsr); + if (pubKey == NULL) { + SIGNATURE_TOOLS_LOGE("X509_REQ_get_pubkey failed"); + goto err; + } + if (caPrikey == nullptr || rootcsr == nullptr || subcsr == nullptr) { + SIGNATURE_TOOLS_LOGE("Sign failed because of caPrikey, roocsr or subcsr is nullptr"); + goto err; + } + result = (!X509_set_pubkey(cert, pubKey)); + if (result) { + SIGNATURE_TOOLS_LOGE("X509_set_pubkey failed"); + goto err; + } + result = (!X509_set_issuer_name(cert, issuerName)); + if (result) { + SIGNATURE_TOOLS_LOGE("X509_set_issuer_name failed"); + goto err; + } + result = (!X509_set_subject_name(cert, subjectName)); + if (result) { + SIGNATURE_TOOLS_LOGE("X509_set_subject_name failed"); + goto err; + } + result = (!SignCert(cert, caPrikey, signAlg)); + if (result) { + goto err; + } + EVP_PKEY_free(pubKey); + return true; +err: + EVP_PKEY_free(pubKey); + X509_NAME_free(issuerName); + X509_NAME_free(subjectName); + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + return false; +} + +X509* CertTools::SignCsrGenerateCert(X509_REQ* rootcsr, X509_REQ* subcsr, + EVP_PKEY* keyPair, Options* options) +{ + bool result = false; + X509* cert = X509_new(); + int validity = options->GetInt(Options::VALIDITY); + result = (!SetCertVersion(cert, DEFAULT_CERT_VERSION) || + !SetCertSerialNum(cert)); + if (result) { + goto err; + } + result = SetCertValidity(cert, validity); + if (!result) { + goto err; + } + result = (!SetBisicConstraintsPathLen(options, cert) || + !SetKeyIdentifierExt(cert) || + !SetAuthorizeKeyIdentifierExt(cert)|| + !SetKeyUsage(cert, options) || + !SignForSubCert(cert, subcsr, rootcsr, keyPair, options)); + if (result) { + goto err; + } + return cert; +err: + X509_free(cert); + return nullptr; +} + +bool CertTools::SetSubjectForCert(X509_REQ* certReq, X509* cert) +{ + if (certReq == nullptr) { + SIGNATURE_TOOLS_LOGE("set subjcet failed because of certReq is nullptr"); + goto err; + } + + if (X509_set_subject_name(cert, X509_REQ_get_subject_name(certReq)) != 1) { + SIGNATURE_TOOLS_LOGE("X509_set_issuer_name failed"); + goto err; + } + + if (X509_set_issuer_name(cert, X509_REQ_get_subject_name(certReq)) != 1) { + SIGNATURE_TOOLS_LOGE("X509_set_issuer_name failed"); + goto err; + } + return true; +err: + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + return false; +} + +X509* CertTools::GenerateRootCertificate(EVP_PKEY* keyPair, X509_REQ* certReq, Options* options) +{ + bool result = false; + X509* cert = X509_new(); + int validity = options->GetInt(Options::VALIDITY); + std::string signAlg = options->GetString(Options::SIGN_ALG); + result = (!SetCertVersion(cert, DEFAULT_CERT_VERSION) || + !SetCertSerialNum(cert)); + if (result) { + goto err; + } + if (!SetCertValidityStartAndEnd(cert, DEFAULT_START_VALIDITY, validity)) { + goto err; + } + result = (!SetBisicConstraintsPathLen(options, cert) || + !SetSubjectForCert(certReq, cert) || + !SetCertPublickKey(cert, certReq) || + !SetKeyIdentifierExt(cert) || + !SetKeyUsage(cert, options)); + if (result) { + goto err; + } + result = (!SignCert(cert, keyPair, signAlg)); + if (result) { + goto err; + } + return cert; +err: + X509_free(cert); + return nullptr; +} + +X509* CertTools::GenerateSubCert(EVP_PKEY* keyPair, X509_REQ* rootcsr, Options* options) +{ + std::unique_ptr adapter = std::make_unique< LocalizationAdapter>(options); + EVP_PKEY* subKey = nullptr; + X509_REQ* subcsr = nullptr; + X509* subCert = nullptr; + subKey = adapter->GetAliasKey(false); + if (subKey == nullptr) { + SIGNATURE_TOOLS_LOGE("failed to get the keypair"); + goto err; + } + subcsr = CertTools::GenerateCsr(subKey, options->GetString(Options::SIGN_ALG), + options->GetString(Options::SUBJECT)); + if (subcsr == nullptr) { + SIGNATURE_TOOLS_LOGE("failed to generate csr"); + goto err; + } + subCert = SignCsrGenerateCert(rootcsr, subcsr, keyPair, options); + if (subCert == nullptr) { + SIGNATURE_TOOLS_LOGE("failed to generate the subCert"); + goto err; + } + EVP_PKEY_free(subKey); + X509_REQ_free(subcsr); + return subCert; +err: + EVP_PKEY_free(subKey); + X509_REQ_free(subcsr); + return nullptr; +} + +bool CertTools::SetKeyUsage(X509* cert, Options* options) +{ + std::string keyUsage = options->GetString(Options::KEY_USAGE); + ASN1_INTEGER* keyUsageInt = ASN1_INTEGER_new(); + long key = 0; + if (keyUsage.empty()) { + key = X509v3_KU_KEY_CERT_SIGN | X509v3_KU_CRL_SIGN; + if (keyUsageInt == NULL || !ASN1_INTEGER_set(keyUsageInt, key)) { + SIGNATURE_TOOLS_LOGE("failed to set asn1_integer"); + ASN1_INTEGER_free(keyUsageInt); + return false; + } + if (!X509_add1_ext_i2d(cert, NID_key_usage, keyUsageInt, 0, X509V3_ADD_DEFAULT)) { + SIGNATURE_TOOLS_LOGE("failed to add ext"); + ASN1_INTEGER_free(keyUsageInt); + return false; + } + } else { + bool keyUsageCritical = options->GetBool(Options::KEY_USAGE_CRITICAL); + int crit = keyUsageCritical > 0 ? 1 : 0; + std::vector vecs = StringUtils::SplitString(keyUsage.c_str(), ','); + for (auto &vec : vecs) { + key |= externDic[vec]; + } + if (keyUsageInt == NULL || !ASN1_INTEGER_set(keyUsageInt, key)) { + SIGNATURE_TOOLS_LOGE("failed to set asn1_integer"); + ASN1_INTEGER_free(keyUsageInt); + return false; + } + if (!X509_add1_ext_i2d(cert, NID_key_usage, keyUsageInt, crit, X509V3_ADD_DEFAULT)) { + SIGNATURE_TOOLS_LOGE("failed to add ext"); + ASN1_INTEGER_free(keyUsageInt); + return false; + } + } + ASN1_INTEGER_free(keyUsageInt); + return true; +} + +bool CertTools::SetkeyUsageExt(X509* cert, Options* options) +{ + X509_EXTENSION* ext = nullptr; + bool keyUsageCritical = options->GetBool(Options::KEY_USAGE_CRITICAL); + int crit = keyUsageCritical ? 1 : 0; + if (!options->GetString(Options::EXT_KEY_USAGE).empty()) { + ext = X509V3_EXT_conf(NULL, NULL, NID_EXT_KEYUSAGE_CONST.c_str(), + externKey[options->GetString(Options::EXT_KEY_USAGE)].c_str()); + if (!X509_EXTENSION_set_critical(ext, crit)) { + SIGNATURE_TOOLS_LOGE("failed to set critical for extKeyUsage "); + X509_EXTENSION_free(ext); + return false; + } + if (!X509_add_ext(cert, ext, -1)) { + SIGNATURE_TOOLS_LOGE("failed to add extension"); + X509_EXTENSION_free(ext); + return false; + } + } + X509_EXTENSION_free(ext); + return true; +} + +bool CertTools::SetExpandedInformation(X509* cert, Options* options) +{ + bool result = false; + result = (!SetKeyUsage(cert, options) || + !SetkeyUsageExt(cert, options)); + if (result) { + SIGNATURE_TOOLS_LOGE("Failed to set expanded information "); + return false; + } + return true; +} + +bool CertTools::SetPubkeyAndSignCert(X509* cert, X509_REQ* issuercsr, + X509_REQ* certReq, EVP_PKEY* keyPair, Options* options) +{ + if (!X509_set_issuer_name(cert, X509_REQ_get_subject_name(issuercsr))) { + SIGNATURE_TOOLS_LOGE("X509_set_issuer_name failed"); + goto err; + } + + if (!X509_set_subject_name(cert, X509_REQ_get_subject_name(certReq))) { + SIGNATURE_TOOLS_LOGE("X509_set_subject_name failed"); + goto err; + } + if ((options->GetString(Options::SIGN_ALG)) == SIGN_ALG_SHA256) { + if (!X509_sign(cert, keyPair, EVP_sha256())) { + SIGNATURE_TOOLS_LOGE("X509_sign failed"); + goto err; + } + } else { + if (!X509_sign(cert, keyPair, EVP_sha384())) { + SIGNATURE_TOOLS_LOGE("X509_sign failed"); + goto err; + } + } + return true; +err: + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + return false; +} + +X509* CertTools::GenerateCert(EVP_PKEY* keyPair, X509_REQ* certReq, Options* options) +{ + int validity = 0; + bool result = false; + X509_REQ* issuercsr = CertTools::GenerateCsr(keyPair, options->GetString(Options::SIGN_ALG), + options->GetString(Options::ISSUER)); + if (issuercsr == nullptr) { + SIGNATURE_TOOLS_LOGE("failed to generate the issuercsr"); + return nullptr; + } + + X509* cert = X509_new(); + result = (!SetCertVersion(cert, DEFAULT_CERT_VERSION) || + !SetCertSerialNum(cert) || + !SetKeyIdentifierExt(cert)); + if (result) { + goto err; + } + validity = options->GetInt(Options::VALIDITY); + if (!SetCertValidityStartAndEnd(cert, DEFAULT_START_VALIDITY, validity)) { + goto err; + } + + result = (!SetBisicConstraints(options, cert) || + !SetCertPublickKey(cert, certReq) || + !SetExpandedInformation(cert, options) || + !SetPubkeyAndSignCert(cert, issuercsr, certReq, keyPair, options)); + if (result) { + goto err; + } + X509_REQ_free(issuercsr); + return cert; +err: + X509_free(cert); + X509_REQ_free(issuercsr); + return nullptr; +} + +X509_REQ* CertTools::GenerateCsr(EVP_PKEY* evpPkey, std::string signAlgorithm, std::string subject) +{ + X509_NAME* name = nullptr; + X509_REQ* req = X509_REQ_new(); + + if (!X509_REQ_set_pubkey(req, evpPkey)) { + SIGNATURE_TOOLS_LOGE("X509_REQ_set_pubkey failed"); + goto err; + } + + name = BuildDN(subject, req); + if (!name) { + SIGNATURE_TOOLS_LOGE("failed to add subject into cert"); + goto err; + } + + if (signAlgorithm == SIGN_ALG_SHA256) { + if (!X509_REQ_sign(req, evpPkey, EVP_sha256())) { + SIGNATURE_TOOLS_LOGE("X509_REQ_sign failed"); + goto err; + } + } else if (signAlgorithm == SIGN_ALG_SHA384) { + if (!X509_REQ_sign(req, evpPkey, EVP_sha384())) { + SIGNATURE_TOOLS_LOGE("X509_REQ_sign failed"); + goto err; + } + } else { + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, + "Sign algorithm format error! Please check again."); + goto err; + } + return req; +err: + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + X509_REQ_free(req); + return nullptr; +} + +std::string CertTools::CsrToString(X509_REQ* csr) +{ + BIO* csrBio = BIO_new(BIO_s_mem()); + if (!csrBio) { + return ""; + } + if (!PEM_write_bio_X509_REQ(csrBio, csr)) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("PEM_write_bio_X509_REQ error"); + BIO_free(csrBio); + return ""; + } + BUF_MEM* data = nullptr; + BIO_get_mem_ptr(csrBio, &data); + if (!data) { + BIO_free(csrBio); + return ""; + } + if (!data->data) { + BIO_free(csrBio); + return ""; + } + std::string csrStr(data->data, data->length); + BIO_free(csrBio); + return csrStr; +} + +X509* CertTools::ReadfileToX509(const std::string& filename) +{ + BIO* certBio = BIO_new_file(filename.c_str(), "rb"); + if (!certBio) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("BIO_new_file failed"); + BIO_free(certBio); + return nullptr; + } + + X509* cert = X509_new(); + if (!PEM_read_bio_X509(certBio, &cert, NULL, NULL)) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("PEM_read_bio_X509 failed"); + X509_free(cert); + BIO_free(certBio); + return nullptr; + } + BIO_free(certBio); + + return cert; +} + +bool CertTools::SetCertVersion(X509* cert, int versionNum) +{ + if (!X509_set_version(cert, versionNum)) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("set x509 cert version failed"); + return false; + } + return true; +} + +bool CertTools::SetCertSerialNum(X509* cert) +{ + BN_CTX* ctx = BN_CTX_new(); + BIGNUM* bignum = BN_new(); + uint8_t serialNumberValue[RANDOM_SERIAL_NUMBER_LENGTH] = {0}; + if (!SerialNumberBuilder(serialNumberValue, sizeof(serialNumberValue))) { + goto err; + } + if (!BN_bin2bn(serialNumberValue, sizeof(serialNumberValue), bignum)) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + goto err; + } + if (BN_is_negative(bignum)) { + BN_set_negative(bignum, 0); // Replace negative numbers with positive ones + } + if (!BN_to_ASN1_INTEGER(bignum, X509_get_serialNumber(cert))) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + goto err; + } + BN_CTX_free(ctx); + BN_free(bignum); + return true; +err: + SIGNATURE_TOOLS_LOGE("set x509 cert serial number failed"); + BN_CTX_free(ctx); + BN_free(bignum); + return false; +} + +bool CertTools::SetCertIssuerName(X509* cert, X509_NAME* issuer) +{ + if (!X509_set_issuer_name(cert, issuer)) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("set x509 cert issuer name failed"); + return false; + } + return true; +} + +bool CertTools::SetCertSubjectName(X509* cert, X509_REQ* subjectCsr) +{ + X509_NAME* subject = nullptr; + if (!(subject = X509_REQ_get_subject_name(subjectCsr))) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("get X509 cert subject name failed"); + return false; + } + if (!X509_set_subject_name(cert, subject)) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("set X509 cert subject name failed"); + return false; + } + return true; +} + +bool CertTools::SetCertValidityStartAndEnd(X509* cert, long vilidityStart, long vilidityEnd) +{ + if (!X509_gmtime_adj(X509_getm_notBefore(cert), vilidityStart)) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("set cert vilidity start time failed"); + return false; + } + if (!X509_gmtime_adj(X509_getm_notAfter(cert), vilidityEnd)) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("set cert vilidity end time failed"); + return false; + } + return true; +} + +bool CertTools::SetCertPublickKey(X509* cert, X509_REQ* subjectCsr) +{ + EVP_PKEY* publicKey = X509_REQ_get_pubkey(subjectCsr); + if (!publicKey) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("get the pubkey from csr failed"); + return false; + } + if (!X509_set_pubkey(cert, publicKey)) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + EVP_PKEY_free(publicKey); + SIGNATURE_TOOLS_LOGE("set public key to cert failed"); + return false; + } + EVP_PKEY_free(publicKey); + return true; +} + +bool CertTools::SetBasicExt(X509* cert) +{ + X509_EXTENSION* basicExtension = X509V3_EXT_conf(NULL, NULL, NID_BASIC_CONST.c_str(), + DEFAULT_BASIC_EXTENSION.c_str()); + if (!X509_add_ext(cert, basicExtension, -1)) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("set basicExtension information failed"); + X509_EXTENSION_free(basicExtension); + return false; + } + X509_EXTENSION_free(basicExtension); + return true; +} + +bool CertTools::SetkeyUsageExt(X509* cert) +{ + X509_EXTENSION* keyUsageExtension = X509V3_EXT_conf(NULL, NULL, NID_KEYUSAGE_CONST.c_str(), + DEFAULT_KEYUSAGE_EXTENSION.c_str()); + if (!X509_add_ext(cert, keyUsageExtension, -1)) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("set keyUsageExtension information failed"); + X509_EXTENSION_free(keyUsageExtension); + return false; + } + X509_EXTENSION_free(keyUsageExtension); + return true; +} + +bool CertTools::SetKeyUsageEndExt(X509* cert) +{ + X509_EXTENSION* keyUsageEndExtension = X509V3_EXT_conf(NULL, NULL, NID_EXT_KEYUSAGE_CONST.c_str(), + DEFAULT_EXTEND_KEYUSAGE.c_str()); + if (!X509_add_ext(cert, keyUsageEndExtension, -1)) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("set keyUsageEndExtension information failed"); + X509_EXTENSION_free(keyUsageEndExtension); + return false; + } + X509_EXTENSION_free(keyUsageEndExtension); + return true; +} + +bool CertTools::SetKeyIdentifierExt(X509* cert) +{ + unsigned char digest[SHA256_DIGEST_LENGTH] = {0}; + unsigned int digestLen = 0; + if (X509_pubkey_digest(cert, EVP_sha256(), digest, &digestLen) != 1) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("digest x509 cert public key failed"); + return false; + } + ASN1_OCTET_STRING* pubKeyDigestData = ASN1_OCTET_STRING_new(); + if (!ASN1_OCTET_STRING_set(pubKeyDigestData, digest, digestLen)) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("set ANS1 pubKeyDigestData failed"); + ASN1_OCTET_STRING_free(pubKeyDigestData); + return false; + } + + X509_EXTENSION* subKeyIdentifierExtension = nullptr; + /* function OBJ_nid2obj(NID_subject_key_identifier) return value is a global variable, so should not free it */ + subKeyIdentifierExtension = X509_EXTENSION_create_by_OBJ(NULL, OBJ_nid2obj(NID_subject_key_identifier), + 0, pubKeyDigestData); + if (!X509_add_ext(cert, subKeyIdentifierExtension, -1)) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("set subKeyIdentifierExtension information failed"); + ASN1_OCTET_STRING_free(pubKeyDigestData); + X509_EXTENSION_free(subKeyIdentifierExtension); + return false; + } + ASN1_OCTET_STRING_free(pubKeyDigestData); + X509_EXTENSION_free(subKeyIdentifierExtension); + return true; +} + +bool CertTools::SetAuthorizeKeyIdentifierExt(X509* cert) +{ + unsigned char key_id[] = { 0x73, 0x3a, 0x81, 0x87, 0x8f, 0x95, 0xc1, 0x94, + 0xcf, 0xef, 0xab, 0x6f, 0x7f, 0x01, 0x52, 0x86, + 0xa3, 0xc2, 0x01, 0xc2 }; + unsigned int key_id_len = sizeof(key_id); + X509_EXTENSION* ext = nullptr; + AUTHORITY_KEYID* akid = AUTHORITY_KEYID_new(); + akid->keyid = ASN1_OCTET_STRING_new(); + if (!ASN1_OCTET_STRING_set(akid->keyid, key_id, key_id_len)) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("set ANS1 pubKeyDigestData failed"); + AUTHORITY_KEYID_free(akid); + return false; + } + ext = X509V3_EXT_i2d(NID_authority_key_identifier, 1, akid); + if (!X509_add_ext(cert, ext, -1)) { + SIGNATURE_TOOLS_LOGE("Failed to add AKI extension to certificate"); + X509_EXTENSION_free(ext); + AUTHORITY_KEYID_free(akid); + return false; + } + + X509_EXTENSION_free(ext); + AUTHORITY_KEYID_free(akid); + return true; +} + +bool CertTools::SetSignCapacityExt(X509* cert, const char signCapacity[], int capacityLen) +{ + ASN1_OCTET_STRING* certSignCapacityData = ASN1_OCTET_STRING_new(); + if (!ASN1_OCTET_STRING_set(certSignCapacityData, (const unsigned char*)signCapacity, capacityLen)) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("failed to set pubkey digst into ASN1 object"); + ASN1_OCTET_STRING_free(certSignCapacityData); + return false; + } + // generate user-define Nid + ASN1_OBJECT* nid = OBJ_txt2obj(X509_EXT_OID.c_str(), 1); + X509_EXTENSION* certSignCapacityExt = X509_EXTENSION_create_by_OBJ(NULL, nid, 0, certSignCapacityData); + + if (!X509_add_ext(cert, certSignCapacityExt, -1)) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("set certSignCapacityExt information failed"); + ASN1_OBJECT_free(nid); + X509_EXTENSION_free(certSignCapacityExt); + ASN1_OCTET_STRING_free(certSignCapacityData); + return false; + } + ASN1_OBJECT_free(nid); + X509_EXTENSION_free(certSignCapacityExt); + ASN1_OCTET_STRING_free(certSignCapacityData); + return true; +} + +bool CertTools::SignCert(X509* cert, EVP_PKEY* privateKey, std::string signAlg) +{ + const EVP_MD* alg = nullptr; + if (signAlg == SIGN_ALG_SHA256) { + /* in openssl this func return value is stack variable, so we not need to release it */ + alg = EVP_sha256(); + } + if (signAlg == SIGN_ALG_SHA384) { + alg = EVP_sha384(); + } + if (!X509_sign(cert, privateKey, alg)) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("sign X509 cert failed"); + return false; + } + return true; +} + +bool CertTools::SetCertValidity(X509* cert, int validity) +{ + if (!SetCertValidityStartAndEnd(cert, DEFAULT_START_VALIDITY, validity)) { + return false; + } + return true; +} + +bool CertTools::SerialNumberBuilder(uint8_t* serialNum, int length) +{ + if (RAND_bytes(serialNum, length) != 1) { // this function is thread safity + SIGNATURE_TOOLS_LOGE("serial number build failed"); + return false; + } + return true; +} + +X509* CertTools::GenerateEndCert(X509_REQ* csr, EVP_PKEY* issuerKeyPair, + LocalizationAdapter& adapter, + const char signCapacity[], int capacityLen) +{ + X509* cert = X509_new(); // in this function, should not release X509cert memory + X509_REQ* issuerReq = nullptr; + bool result = false; + issuerReq = X509_REQ_new(); + std::string issuerStr = adapter.options->GetString(adapter.options->ISSUER); + int validity = adapter.options->GetInt(adapter.options->VALIDITY); + std::string signAlg = adapter.options->GetString(adapter.options->SIGN_ALG); + + result = (!SetCertVersion(cert, DEFAULT_CERT_VERSION) || !SetCertSerialNum(cert)); + if (result) { + goto err; + } + result = (!SetCertIssuerName(cert, BuildDN(issuerStr, issuerReq)) || !SetCertSubjectName(cert, csr)); + if (result) { + goto err; + } + result = (!SetCertValidity(cert, validity) || !SetCertPublickKey(cert, csr)); + if (result) { + goto err; + } + result = (!SetBasicExt(cert) || !SetkeyUsageExt(cert) || !SetKeyUsageEndExt(cert)); + if (result) { + goto err; + } + result = (!SetKeyIdentifierExt(cert) || !SetSignCapacityExt(cert, signCapacity, capacityLen)); + if (result) { + goto err; + } + if (!SignCert(cert, issuerKeyPair, signAlg)) { + goto err; + } + + adapter.AppAndProfileAssetsRealse({}, {issuerReq}, {}); + return cert; // return x509 assets +err: + adapter.AppAndProfileAssetsRealse({}, {issuerReq}, {cert}); + return nullptr; +} + +} // namespace SignatureTools +} // namespace OHOS + diff --git a/hapsigntool_cpp/api/src/localization_adapter.cpp b/hapsigntool_cpp/api/src/localization_adapter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..64f5fdeb53c8fd1ccab2d9be06187e4574331652 --- /dev/null +++ b/hapsigntool_cpp/api/src/localization_adapter.cpp @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2024-2024 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" + +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::GetIssureKeyByAlias() +{ + 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"); + VerifyHapOpensslUtils::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 StringUtils::CaseCompare(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/hapsigntool_cpp/api/src/sign_tool_service_impl.cpp b/hapsigntool_cpp/api/src/sign_tool_service_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4067ea69c60b1ec07e57144dd106dd703dd6d2a7 --- /dev/null +++ b/hapsigntool_cpp/api/src/sign_tool_service_impl.cpp @@ -0,0 +1,699 @@ +/* + * Copyright (c) 2024-2024 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 + +#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 "verify_hap.h" +#include "constant.h" +#include "remote_sign_provider.h" +#include "verify_elf.h" +#include "verify_bin.h" + +namespace OHOS { +namespace SignatureTools { + +bool SignToolServiceImpl::GenerateCA(Options* options) +{ + bool flag = true; + std::unique_ptr adapter = std::make_unique(options); + bool isEmpty = FileUtils::IsEmpty(options->GetString(Options::ISSUER_KEY_ALIAS)); + EVP_PKEY* subKey = adapter->GetAliasKey(true); + if (!subKey) { + SIGNATURE_TOOLS_LOGE("failed to get subKey!"); + return false; + } + EVP_PKEY* rootKey = nullptr; + if (isEmpty) { + if (HandleIssuerKeyAliasEmpty(options) == RET_FAILED) { + EVP_PKEY_free(subKey); + return false; + } + flag = GenerateRootCertToFile(options, subKey); + EVP_PKEY_free(subKey); + } else { + if (HandleIsserKeyAliasNotEmpty(options) == RET_FAILED) { + EVP_PKEY_free(subKey); + return false; + } + adapter->SetIssuerKeyStoreFile(true); + rootKey = adapter->GetAliasKey(false); + flag = GenerateSubCertToFile(options, rootKey); + EVP_PKEY_free(rootKey); + EVP_PKEY_free(subKey); + } + adapter->ResetPwd(); + return flag; +} + +bool SignToolServiceImpl::GenerateRootCertToFile(Options* options, EVP_PKEY* rootKey) +{ + std::string signAlg = options->GetString(Options::SIGN_ALG); + std::string subject = options->GetString(Options::SUBJECT); + std::string outFile; + X509* cert = nullptr; + X509_REQ* csr = nullptr; + bool result = false; + if (rootKey == nullptr) { + goto err; + } + csr = CertTools::GenerateCsr(rootKey, signAlg, subject); + if (!csr) { + goto err; + } + cert = CertTools::GenerateRootCertificate(rootKey, csr, options); + if (!cert) { + goto err; + } + if (!X509CertVerify(cert, rootKey)) { + goto err; + } + + if (!OutputModeOfCert(cert, options)) { + goto err; + } + result = true; +err: + if (result == false) + SIGNATURE_TOOLS_LOGE("generate root cert failed!"); + X509_free(cert); + X509_REQ_free(csr); + return result; +} + +bool SignToolServiceImpl::GenerateSubCertToFile(Options* options, EVP_PKEY* rootKey) +{ + std::string signAlg = options->GetString(Options::SIGN_ALG); + std::string issuer = options->GetString(Options::ISSUER); + X509* cert = nullptr; + X509_REQ* csr = nullptr; + bool result = false; + if (rootKey == nullptr) { + goto err; + } + csr = CertTools::GenerateCsr(rootKey, signAlg, issuer); + if (!csr) { + goto err; + } + cert = CertTools::GenerateSubCert(rootKey, csr, options); + if (!cert) { + goto err; + } + if (!X509CertVerify(cert, rootKey)) { + goto err; + } + if (!OutputModeOfCert(cert, options)) { + goto err; + } + result = true; +err: + if (result == false) + SIGNATURE_TOOLS_LOGE("generate sub cert failed!"); + X509_free(cert); + X509_REQ_free(csr); + return result; +} + +int SignToolServiceImpl::HandleIssuerKeyAliasEmpty(Options* options) +{ + std::string iksFile = options->GetString(Options::ISSUER_KEY_STORE_FILE); + if (!FileUtils::IsEmpty(iksFile) && !options->Equals(Options::KEY_STORE_FILE, Options::ISSUER_KEY_STORE_FILE)) { + PrintErrorNumberMsg("WRITE_FILE_ERROR", IO_ERROR, + "Parameter '" + iksFile + "' and parameter '" + + options->GetString(Options::KEY_STORE_FILE) + "' are inconsistent"); + return RET_FAILED; + } + char* keyStoreRights = options->GetChars(Options::KEY_STORE_RIGHTS); + char* issuerKeyStoreRights = options->GetChars(Options::ISSUER_KEY_STORE_RIGHTS); + if (!FileUtils::IsEmpty(iksFile)) { + if ((keyStoreRights == nullptr && issuerKeyStoreRights != nullptr) || + (keyStoreRights != nullptr && issuerKeyStoreRights == nullptr)) { + goto err; + } else if (keyStoreRights == nullptr && issuerKeyStoreRights == nullptr) { + return RET_OK; + } else { + if (std::strcmp(keyStoreRights, issuerKeyStoreRights) != 0) { + goto err; + } + } + } + return RET_OK; +err: + PrintErrorNumberMsg("WRITE_FILE_ERROR", IO_ERROR, + "Parameter 'keystorePwd' and parameter 'issuerKeystorePwd' are inconsistent"); + return RET_FAILED; +} + +int SignToolServiceImpl::HandleIsserKeyAliasNotEmpty(Options* options) +{ + std::string iksFile = options->GetString(Options::ISSUER_KEY_STORE_FILE); + if (!FileUtils::IsEmpty(iksFile)) { + if (!FileUtils::ValidFileType(iksFile, {"p12", "jks"})) { + SIGNATURE_TOOLS_LOGE("issuer keystore file type is inconsistent!"); + return RET_FAILED; + } + } + return RET_OK; +} + +bool SignToolServiceImpl::OutputModeOfCert(X509* cert, Options* options) +{ + std::string outFile = options->GetString(Options::OUT_FILE); + if (!outFile.empty()) { + if (!CertTools::SaveCertTofile(outFile, cert)) { + PrintErrorNumberMsg("WRITE_FILE_ERROR", IO_ERROR, "failed to save cert to file"); + return false; + } + } else { + if (!PrintX509CertFromMemory(cert)) { + return false; + } + } + return true; +} + +bool SignToolServiceImpl::GenerateCert(Options* options) +{ + std::unique_ptr adapter = std::make_unique(options); + std::string signAlg = options->GetString(Options::SIGN_ALG); + std::string subject = options->GetString(Options::SUBJECT); + EVP_PKEY* subjectkeyPair = nullptr; + EVP_PKEY* rootKeyPair = nullptr; + X509_REQ* csr = nullptr; + X509* cert = nullptr; + bool result = false; + subjectkeyPair = adapter->GetAliasKey(false); + if (!subjectkeyPair) { + goto err; + } + adapter->SetIssuerKeyStoreFile(true); + rootKeyPair = adapter->GetIssureKeyByAlias(); + if (!rootKeyPair) { + goto err; + } + adapter->ResetPwd(); + csr = CertTools::GenerateCsr(subjectkeyPair, signAlg, subject); + if (!csr) { + goto err; + } + cert = CertTools::GenerateCert(rootKeyPair, csr, options); + if (!cert) { + goto err; + } + if (!X509CertVerify(cert, rootKeyPair)) { + goto err; + } + if (!OutputModeOfCert(cert, options)) { + goto err; + } + result = true; +err: + if (result == false) + SIGNATURE_TOOLS_LOGE("generate cert failed!"); + X509_free(cert); + X509_REQ_free(csr); + EVP_PKEY_free(rootKeyPair); + EVP_PKEY_free(subjectkeyPair); + return result; +} + +bool SignToolServiceImpl::GenerateKeyStore(Options* options) +{ + std::unique_ptr adaptePtr = std::make_unique(options); + std::string keyAlias = adaptePtr->options->GetString(Options::KEY_ALIAS); + + int status = adaptePtr->IsAliasExist(keyAlias); + if (status == RET_OK) { + adaptePtr->ResetPwd(); + PrintErrorNumberMsg("KEY_ALIAS_ERROR", KEY_ALIAS_ERROR, "'" + keyAlias + + "' key alias already exists and cannot be generated repeatedly"); + return false; + } + + if (!adaptePtr->keyStoreHelper->GetPassWordStatus()) { + adaptePtr->ResetPwd(); + return false; + } + + EVP_PKEY* keyPair = nullptr; + keyPair = adaptePtr->GetAliasKey(true); + adaptePtr->ResetPwd(); + if (keyPair == nullptr) { + SIGNATURE_TOOLS_LOGE("failed to get keypair!"); + return false; + } + EVP_PKEY_free(keyPair); + return true; +} + +bool SignToolServiceImpl::GenerateCsr(Options* options) +{ + std::unique_ptr adapter = std::make_unique(options); + EVP_PKEY* keyPair = adapter->GetAliasKey(false); + if (!keyPair) { + SIGNATURE_TOOLS_LOGE("failed to get keypair!"); + adapter->ResetPwd(); + return false; + } + adapter->ResetPwd(); + X509_REQ* csr = nullptr; + std::string signAlg = options->GetString(Options::SIGN_ALG); + std::string subject = options->GetString(Options::SUBJECT); + if (signAlg.empty()) { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", + INVALIDPARAM_ERROR, + "Please check if signalg has been specified which is required."); + EVP_PKEY_free(keyPair); + return false; + } + if (subject.empty()) { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", + INVALIDPARAM_ERROR, + "Please check if subject has been specified which is required."); + EVP_PKEY_free(keyPair); + return false; + } + csr = CertTools::GenerateCsr(keyPair, signAlg, subject); + if (!csr) { + SIGNATURE_TOOLS_LOGE("failed to generate csr request!"); + EVP_PKEY_free(keyPair); + return false; + } + std::string csrStr = CertTools::CsrToString(csr); + EVP_PKEY_free(keyPair); + X509_REQ_free(csr); + if (csrStr.size() == 0) { + PrintErrorNumberMsg("PARSE_ERROR", PARSE_ERROR, + "failed to transform csr to string!"); + return false; + } + std::string outFile = options->GetString(Options::OUT_FILE); + return OutputString(csrStr, outFile); +} + +bool SignToolServiceImpl::OutputString(std::string content, std::string file) +{ + if (file.size() == 0) { + puts(content.c_str()); + return true; + } + std::ofstream outFile(file.c_str()); + if (!outFile.is_open()) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, + "failed to open the outFile " + file + " !"); + return false; + } + outFile << content; + outFile.close(); + return true; +} + +bool SignToolServiceImpl::X509CertVerify(X509* cert, EVP_PKEY* privateKey) +{ + if (!X509_verify(cert, privateKey)) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "private key verify cert failed!"); + return false; + } + return true; +} + +X509_REQ* SignToolServiceImpl::GetCsr(EVP_PKEY* keyPair, std::string signAlg, std::string subject) +{ + if (signAlg.empty() || subject.empty()) { + SIGNATURE_TOOLS_LOGE("failed to get signalg or subject!"); + return nullptr; + } + X509_REQ* csr = CertTools::GenerateCsr(keyPair, signAlg, subject); + if (!csr) { + SIGNATURE_TOOLS_LOGE("failed to generate csr!"); + return nullptr; + } + return csr; +} + +bool SignToolServiceImpl::GenerateAppCert(Options* options) +{ + std::unique_ptr adapter = std::make_unique(options); + EVP_PKEY* keyPair = nullptr; + EVP_PKEY* issueKeyPair = nullptr; + X509_REQ* csr = nullptr; + X509* x509Certificate = nullptr; + std::string signAlg = adapter->options->GetString(Options::SIGN_ALG); + std::string subject = adapter->options->GetString(Options::SUBJECT); + + if (!(keyPair = adapter->GetAliasKey(false))) { // get keypair + goto err; + } + adapter->SetIssuerKeyStoreFile(true); + if (!(issueKeyPair = adapter->GetIssureKeyByAlias())) { // get issuer keypair + goto err; + } + adapter->ResetPwd(); // clean pwd for safety + csr = GetCsr(keyPair, signAlg, subject); + if (!csr) { // get CSR request + goto err; + } + x509Certificate = CertTools::GenerateEndCert(csr, issueKeyPair, *adapter, + APP_SIGNING_CAPABILITY, + sizeof(APP_SIGNING_CAPABILITY)); // get app x509 cert + if (!x509Certificate) { + PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, "generate app cert failed"); + goto err; + } + if (!X509CertVerify(x509Certificate, issueKeyPair)) { + goto err; + } + if (!GetAndOutPutCert(*adapter, x509Certificate)) { + goto err; + } + + adapter->AppAndProfileAssetsRealse({issueKeyPair, keyPair}, {csr}, {x509Certificate}); // realse heap memory + return true; + +err: + adapter->AppAndProfileAssetsRealse({issueKeyPair, keyPair}, {csr}, {x509Certificate}); + return false; +} + +bool SignToolServiceImpl::GenerateProfileCert(Options* options) +{ + std::unique_ptr adapter = std::make_unique(options); + EVP_PKEY* keyPair = nullptr; + EVP_PKEY* issueKeyPair = nullptr; + X509_REQ* csr = nullptr; + X509* x509Certificate = nullptr; + std::string signAlg = adapter->options->GetString(Options::SIGN_ALG); + std::string subject = adapter->options->GetString(Options::SUBJECT); + + if (!(keyPair = adapter->GetAliasKey(false))) { // get keypair + goto err; + } + adapter->SetIssuerKeyStoreFile(true); + if (!(issueKeyPair = adapter->GetIssureKeyByAlias())) { // get issuer keypair + goto err; + } + adapter->ResetPwd(); // clean pwd for safety + csr = GetCsr(keyPair, signAlg, subject); + if (!csr) { // get CSR request + goto err; + } + x509Certificate = CertTools::GenerateEndCert(csr, issueKeyPair, *adapter, + PROFILE_SIGNING_CAPABILITY, + sizeof(PROFILE_SIGNING_CAPABILITY)); // get profile x509 cert + if (!x509Certificate) { + PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, "generate profile cert failed"); + goto err; + } + if (!X509CertVerify(x509Certificate, issueKeyPair)) { + goto err; + } + if (!GetAndOutPutCert(*adapter, x509Certificate)) { // output cert to file + goto err; + } + + adapter->AppAndProfileAssetsRealse({issueKeyPair, keyPair}, {csr}, {x509Certificate}); // realse heap memory + return true; + +err: + adapter->AppAndProfileAssetsRealse({issueKeyPair, keyPair}, {csr}, {x509Certificate}); + return false; +} + +bool SignToolServiceImpl::GetAndOutPutCert(LocalizationAdapter& adapter, X509* cert) +{ + std::string outFile = adapter.options->GetString(Options::OUT_FILE); + bool successflag = false; + X509* subCaCert = nullptr; + X509* rootCaCert = nullptr; + std::vector certificates; + if (adapter.IsOutFormChain()) { + certificates.emplace_back(cert); // add entity cert + successflag = (!(subCaCert = adapter.GetSubCaCertFile()) || + !(rootCaCert = adapter.GetCaCertFile())); + if (successflag) { + return false; + } + certificates.emplace_back(subCaCert); // add sub ca cert + certificates.emplace_back(rootCaCert); // add root ca cert + + if (outFile.empty()) { + successflag = PrintX509CertChainFromMemory(certificates); // print certchain to cmd + adapter.AppAndProfileAssetsRealse({}, {}, {certificates[1], certificates[2]}); + return successflag; + } + successflag = OutPutCertChain(certificates, adapter.GetOutFile()); // out put certchain to file + adapter.AppAndProfileAssetsRealse({}, {}, {certificates[1], certificates[2]}); + return successflag; + } + + if (outFile.empty()) { + successflag = PrintX509CertFromMemory(cert); // print cert to cmd + return successflag; + } + successflag = OutPutCert(cert, adapter.GetOutFile()); // out put cert to file + return successflag; +} + +bool SignToolServiceImpl::SignProfile(Options* options) +{ + LocalizationAdapter adapter(options); + const std::string inFile = adapter.GetInFile(); + const std::string outFile = adapter.GetOutFile(); + std::string provisionContent; + std::string p7b; + if (SignToolServiceImpl::GetProvisionContent(inFile, provisionContent) < 0) { + SIGNATURE_TOOLS_LOGE("getProvisionContent failed"); + return false; + } + if (ProfileSignTool::GenerateP7b(adapter, provisionContent, p7b) < 0) { + SIGNATURE_TOOLS_LOGE("generate P7b data failed"); + return false; + } + if (FileUtils::Write(p7b, outFile) < 0) { + SIGNATURE_TOOLS_LOGE("write p7b data failed"); + return false; + } + return true; +} + +bool SignToolServiceImpl::SignHap(Options* 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; + } + std::string inForm = options->GetString(Options::INFORM); + if (ZIP == inForm) { + return signProvider->Sign(options); + } else if (ELF == inForm) { + return signProvider->SignElf(options); + } else { + return signProvider->SignBin(options); + } + return true; +} + +bool SignToolServiceImpl::VerifyProfile(Options* options) +{ + LocalizationAdapter adapter(options); + std::string p7b; + if (FileUtils::ReadFile(adapter.GetInFile(), p7b) < 0) { + SIGNATURE_TOOLS_LOGE("read p7b data error"); + return false; + } + PKCS7Data p7Data; + if (p7Data.Parse(p7b) < 0) { + SIGNATURE_TOOLS_LOGE("verify profile failed"); + return false; + } + if (p7Data.Verify() < 0) { + SIGNATURE_TOOLS_LOGE("verify profile failed"); + return false; + } + const std::string outFile = adapter.GetOutFile(); + std::string originalData; + if (p7Data.GetContent(originalData) < 0) { + SIGNATURE_TOOLS_LOGE("get content failed"); + return false; + } + if (outFile.empty()) { + PrintMsg(originalData); + } else { + std::ofstream out(outFile, std::ios::binary); + out.write(originalData.data(), originalData.size()); + } + return true; +} + +bool SignToolServiceImpl::OutPutCertChain(std::vector& certs, const std::string& outPutPath) +{ + SIGNATURE_TOOLS_LOGD("outPutPath = %s", outPutPath.c_str()); + BIO* bio = nullptr; + if (!(bio = BIO_new_file(outPutPath.c_str(), "wb"))) { + SIGNATURE_TOOLS_LOGE("failed to open file %s", outPutPath.c_str()); + goto err; + } + for (auto cert : certs) { + if (PEM_write_bio_X509(bio, cert) < 0) { + SIGNATURE_TOOLS_LOGE("failed to write certChain to file!"); + goto err; + } + } + BIO_free(bio); + return true; +err: + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + BIO_free(bio); + return false; +} + +bool SignToolServiceImpl::OutPutCert(X509* cert, const std::string& outPutPath) +{ + BIO* bio = BIO_new_file(outPutPath.c_str(), "wb"); + if (!bio) { + SIGNATURE_TOOLS_LOGE("failed to open file: %s", outPutPath.c_str()); + goto err; + } + if (!PEM_write_bio_X509(bio, cert)) { + SIGNATURE_TOOLS_LOGE("failed to write cert to file!"); + goto err; + } + BIO_free(bio); + return true; +err: + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + BIO_free(bio); + return false; +} + +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())) { + SIGNATURE_TOOLS_LOGE("Parsing appProvision failed!"); + PrintErrorNumberMsg("PARSE ERROR", PARSE_ERROR, "Parsing appProvision 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::PrintX509CertFromMemory(X509* cert) +{ + BIO* bio = BIO_new(BIO_s_mem()); + if (!bio) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + return false; + } + if (PEM_write_bio_X509(bio, cert) == 1) { + BUF_MEM* bptr; + BIO_get_mem_ptr(bio, &bptr); + PrintMsg(std::string(bptr->data, bptr->length)); + } else { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "print x509 cert falied"); + BIO_free(bio); + return false; + } + BIO_free(bio); + return true; +} + +bool SignToolServiceImpl::PrintX509CertChainFromMemory(std::vector certs) +{ + for (auto cert : certs) { + BIO* bio = BIO_new(BIO_s_mem()); + BUF_MEM* bptr = nullptr; + if (!bio) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + return false; + } + if (PEM_write_bio_X509(bio, cert) == 1) { + BIO_get_mem_ptr(bio, &bptr); + PrintMsg(std::string(bptr->data, bptr->length)); + } else { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "print x509 cert chain falied"); + BIO_free(bio); + return false; + } + BIO_free(bio); + } + return true; +} + +bool SignToolServiceImpl::VerifyHapSigner(Options* option) +{ + std::string inForm = option->GetString(ParamConstants::PARAM_IN_FORM); + if (inForm == ZIP) { + HapVerifyResult hapVerifyResult; + VerifyHap hapVerifyV2; + int32_t ret = hapVerifyV2.Verify(option->GetString(Options::IN_FILE), hapVerifyResult, option); + if (ret == VERIFY_SUCCESS) { + PrintMsg("hap verify successed!"); + return true; + } + PrintMsg("hap verify failed !"); + return false; + } else if (inForm == ELF) { + VerifyElf verifyElf; + if (!verifyElf.Verify(option)) { + PrintMsg("elf verify failed!"); + return false; + } + PrintMsg("elf verify successed!"); + return true; + } else if (inForm == BIN) { + VerifyBin verifyBin; + if (!verifyBin.Verify(option)) { + PrintMsg("bin verify failed!"); + return false; + } + PrintMsg("bin verify successed!"); + return true; + } else { + PrintErrorNumberMsg("NOT_SUPPORT_ERROR", NOT_SUPPORT_ERROR, "This requirement was not implemented !"); + return false; + } +} + +} // namespace SignatureTools +} // namespace OHOS diff --git a/hapsigntool_cpp/bundle.json b/hapsigntool_cpp/bundle.json new file mode 100644 index 0000000000000000000000000000000000000000..decf68af895587a4a21559bb48f55ac9368a1ac9 --- /dev/null +++ b/hapsigntool_cpp/bundle.json @@ -0,0 +1,53 @@ +{ + "name": "@ohos/hapsigner", + "version": "3.1", + "description": "hap包签名工具,支持.hsp、.hqf、.hap和.app等文件签名", + "homePage": "https://gitee.com/openharmony", + "license": "Apache License 2.0", + "repository": "https://gitee.com/openharmony/developtools_hapsigner", + "domain": "os", + "language": "", + "publishAs": "code-segment", + "private": false, + "scripts": {}, + "tags": [ + "developtools" + ], + "keywords": [ + "hapsigner" + ], + "envs": {}, + "dirs": {}, + "segment": { + "destPath": "developtools/hapsigner" + }, + "component": { + "name": "hapsigner", + "subsystem": "developtools", + "syscap": [], + "features": [], + "adapted_system_type": [ "standard" ], + "rom": "0KB", + "ram": "0KB", + "deps": { + "components": [ + "c_utils", + "json" + ], + "third_party": [ + "bzip2", + "openssl", + "jsoncpp", + "zlib" + ] + }, + "build": { + "sub_component": [ + "//developtools/hapsigner/hapsigntool_cpp:hap-sign-tool" + ], + "inner_kits": [], + "test": [ + ] + } + } +} diff --git a/hapsigntool_cpp/cmd/include/cmd_util.h b/hapsigntool_cpp/cmd/include/cmd_util.h new file mode 100644 index 0000000000000000000000000000000000000000..8bf2238905ced1426f88c20844ccd37a419a4cc7 --- /dev/null +++ b/hapsigntool_cpp/cmd/include/cmd_util.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024-2024 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, size_t size, const ParamsSharedPtr& param); + static bool JudgeAlgType(const std::string& keyAlg); + static bool JudgeSize(const int size); + static bool JudgeSignAlgType(const std::string& signAlg); + static bool VerifyType(const std::string& inputType); + static bool VerifyTypes(const std::string& inputType); + static bool VerifyType(const std::string& inputtype, const std::string& supportTypes); + static bool String2Bool(Options* options, const std::string& option); + 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(ParamsSharedPtr params, const std::string& key, char* value); + static const std::regex INTEGER_PATTERN; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif diff --git a/hapsigntool_cpp/cmd/include/help.h b/hapsigntool_cpp/cmd/include/help.h new file mode 100644 index 0000000000000000000000000000000000000000..43aaeee2b2ffd4ce6f465c3fab6f50953072b269 --- /dev/null +++ b/hapsigntool_cpp/cmd/include/help.h @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2024-2024 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] +USAGE: [options] +)"; + +const std::string KEYPAIR_HELP_TXT = R"( + generate-keypair[options]: + -keyAlias : key alias, required fields; + -keyPwd : key password, optional fields; + -keyAlg : key algorithm, required fields, including ECC; + -keySize : key size, required fields, and the size of the ECC algorithm is NIST-P-256/NIST-P-384; + -keystoreFile : keystore file, required fields, JKS or P12 format; + -keystorePwd : keystore password, optional fields; + -extCfgFile : Extend Profile, optional fields; + + EXAMPLE: + generate-keypair -keyAlias "oh-app1-key-v1" -keyPwd ****** -keyAlg ECC -keySize NIST-P-256 +-keystoreFile "/home/app-keypair.jks" -keystorePwd ****** + generate-keypair -keyAlias "oh-profile-key-v1" -keyPwd ****** -keyAlg ECC -keySize NIST-P-256 +-keystoreFile "/home/profile-keypair.jks" -keystorePwd ****** +)"; + +const std::string CSR_HELP_TXT = R"( + generate-csr[options]: + -keyAlias : key alias, required fields; + -keyPwd : key password, optional fields; + -subject : certificate subject, required fields; + -signAlg : signature algorithm, required fields, including SHA256withECDSA/SHA384withECDSA; + -keystoreFile : keystore file, required fields, JKS or P12 format; + -keystorePwd : keystore password, optional fields; + -outFile : output file, optional fields, if not filled, it will be directly output to the console; + -extCfgFile : Extend Profile, optional fields; + + EXAMPLE: + generate-csr -keyAlias "oh-app1-key-v1" -keyPwd ****** -signAlg SHA256withECDSA -keystorePwd ****** +-subject "C=CN, O=OpenHarmony, OU=OpenHarmony Community, CN=App1 Release" -keystoreFile "/home/app-keypair.jks" +-outFile "/home/oh-app1-key-v1.csr" +)"; + +const std::string CERT_HELP_TXT = R"( + generate-cert[options]: + -keyAlias : key alias, required fields; + -keyPwd : key password, optional fields; + -issuer : issuer subject, required fields; + -issuerKeyAlias : issuer key alias, required fields; + -issuerKeyPwd : issuer key password, optional fields; + -subject : certificate subject, required fields; + -validity : certificate validity, optional fields, the default is 1095 days; + -keyUsage : key usage, required fields, including digitalSignature, nonRepudiation, keyEncipherment, + dataEncipherment, keyAgreement, certificateSignature, crlSignature, encipherOnly and decipherOnly, if the + certificate includes multiple key usages, separate them with commas; + -keyUsageCritical : whether keyUsage is a key item, optional fields, the default is true; + -extKeyUsage : extended key usage, optional fields, including clientAuthentication, serverAuthentication, + codeSignature, emailProtection, smartCardLogin, timestamp, ocspSignature; + -extKeyUsageCritical : whether extKeyUsage is a key item, optional fields, the default is false; + -signAlg : signature algorithm, required fields, includingSHA256withECDSA/SHA384withECDSA; + -basicConstraints : whether to include basicConstraints, optional fields, the default is false; + -basicConstraintsCritical : whether basicConstraints is a key item, optional fields, the default is false; + -basicConstraintsCa : whether it is CA, optional fields, the default is false; + -basicConstraintsPathLen : basicConstraints path length, optional fields, the default is 0; + -keystoreFile : keystore file, required fields, JKS or P12 format; + -keystorePwd : keystore password, optional fields; + -outFile : output file, optional fields, if not filled, it will be directly output to the console; + -extCfgFile : Extend Profile, optional fields; + -issuerKeystoreFile : issuer keystore file, optional fields, JKS or P12 format; + -issuerKeystorePwd : issuer keystore password, optional fields; + + EXAMPLE: + generate-cert -keyAlias "oh-app1-key-v1" -keyPwd ****** -issuerKeyAlias "oh-app-sign-srv-ca-key-v1" +-issuer "C=CN, O=OpenHarmony, OU=OpenHarmony Community, CN=Application Signature Service CA" -issuerKeyPwd ****** +-subject "C=CN, O=OpenHarmony, OU=OpenHarmony Community, CN=App1 Release" -outFile "/home/app1.cer" -keystorePwd ****** +-keyUsage digitalSignature -extKeyUsage codeSignature -signAlg SHA256withECDSA -keystoreFile "/home/app-keypair.jks" +)"; + +const std::string CA_CERT_HELP_TXT = R"( + generate-ca[options]: + -keyAlias : key alias, required fields; + -keyPwd : key password, optional fields; + -keyAlg : key algorithm, required fields, including ECC; + -keySize : key size, required fields, and the size of the ECC algorithm is NIST-P-256/NIST-P-384; + -issuer : issuer subject, optional fields, if it is empty, it means root CA; + -issuerKeyAlias : issuer key alias, optional fields, if it is empty, it means root CA; + -issuerKeyPwd : issuer key password, optional fields; + -subject : certificate subject, required fields; + -validity : certificate validity, optional fields, the default is 3650 days; + -signAlg : signature algorithm, required fields, including SHA256withECDSA/SHA384withECDSA; + -basicConstraintsPathLen : basicConstraints path length, optional fields, the default is 0; + -keystoreFile : keystore file, required fields, JKS or P12 format; + -keystorePwd : keystore password, optional fields; + -outFile : output file, optional fields, if not filled, it will be directly output to the console; + -extCfgFile : Extend Profile, optional fields; + -issuerKeystoreFile : issuer keystore file, optional fields, JKS or P12 format; + -issuerKeystorePwd : issuer keystore password, optional fields; + + EXAMPLE: + generate-ca -keyAlias "oh-root-ca-key-v1" -validity 365 -signAlg SHA384withECDSA -keySize NIST-P-256 + -subject "C=CN, O=OpenHarmony, OU=OpenHarmony Community,CN=Root CA" -keystoreFile "/home/app-keypair.jks" + -keystorePwd ****** -outFile "/home/root-ca.cer" -keyAlg ECC + generate-ca -keyAlias "oh-app1-key-v1" -keyAlg ECC -issuerKeyAlias "oh-sub-app-ca-key-v1" -issuerKeyPwd ****** + -issuer "C=CN, O=OpenHarmony, OU=OpenHarmony Community, CN=Root CA" -keySize NIST-P-256 -validity 365 + -subject "C=CN, O=OpenHarmony, OU=OpenHarmony Community, CN= Application Signature Service CA" -signAlg SHA384withECDSA + -keystoreFile "/home/app-keypair.jks" -keystorePwd ****** -outFile "/home/sub-app-sign-srv-ca.cer" +)"; + +const std::string APP_CERT_HELP_TXT = R"( + generate-app-cert[options]: + -keyAlias : key alias, required fields; + -keyPwd : key password, optional fields; + -issuer : issuer subject, required fields; + -issuerKeyAlias : issuer key alias, required fields; + -issuerKeyPwd : issuer key password, optional fields; + -subject : certificate subject, required fields; + -validity : certificate validity, optional fields, the default is 1095 days; + -signAlg : signature algorithm, required fields, including SHA256withECDSA/SHA384withECDSA; + -keystoreFile : keystore file, required fields, JKS or P12 format; + -keystorePwd : keystore password, optional fields; + -outForm : the format of the output certificate file, including cert/certChain, optional fields, + the default is cert; + -rootCaCertFile : root CA certificate file, required when outForm is certChain; + -subCaCertFile : secondary sub -CA certificate file, required when outForm is certChain; + -outFile : output certificate file(certificate or certificate chain), optional fields, if not filled, + it will be directly output to the console; + -extCfgFile : Extend Profile, optional fields; + -issuerKeystoreFile : issuer keystore file, optional fields, JKS or P12 format; + -issuerKeystorePwd : issuer keystore password, optional fields; + + EXAMPLE: + generate-app-cert -keyAlias "oh-app1-key-v1" -issuerKeyAlias "oh-app-sign-debug-srv-ca-key-v1" -validity 365 +-issuer "C=CN, O=OpenHarmony, OU=OpenHarmony Community, CN=Application Debug Signature Service CA" -keyPwd ****** +-signAlg SHA256withECDSA -keystoreFile "/home/app-keypair.jks" -outFile "/home/app-debug-cert.cer" -outForm cert +-subject "C=CN, O=OpenHarmony, OU=OpenHarmony Community, CN=App1 Debug" -keystorePwd ****** + generate-app-cert -keyAlias "oh-app1-key-v1" -issuerKeyAlias "oh-app-sign-release-srv-ca-key-v1" -validity 365 +-issuer "C=CN, O=OpenHarmony, OU=OpenHarmony Community, CN=Application Release Signature Service CA" -keyPwd ****** +-signAlg SHA256withECDSA -rootCaCertFile "/home/root-ca.cer" -subCaCertFile "/home/sub-app-sign-srv-ca.cer" +-subject "C=CN, O=OpenHarmony, OU=OpenHarmony Community, CN=App1 Release" -keystorePwd ****** -outForm certChain +-keystoreFile "/home/app-keypair.jks" -outFile "/home/app-release-cert.cer" +)"; + +const std::string PROFILE_CERT_HELP_TXT = R"( + generate-profile-cert[options]: + -keyAlias : key alias, required fields; + -keyPwd : key password, optional fields; + -issuer : issuer subject, required fields; + -issuerKeyAlias : issuer key alias, required fields; + -issuerKeyPwd : issuer key password, optional fields; + -subject : certificate subject, required fields; + -validity : certificate validity, optional fields, the default is 1095 days; + -signAlg : signature algorithm, required fields, including SHA256withECDSA/SHA384withECDSA; + -keystoreFile : keystore file, required fields, JKS or P12 format; + -keystorePwd : keystore password, optional fields; + -outForm : the format of the output certificate file, including cert/certChain, optional fields, + the default is cert; + -rootCaCertFile : root CA certificate file, required when outForm is certChain; + -subCaCertFile : secondary sub -CA certificate file, required when outForm is certChain; + -outFile : output file, optional fields, if not filled, it will be directly output to the console; + -extCfgFile : Extend Profile, optional fields; + -issuerKeystoreFile : issuer keystore file, optional fields, JKS or P12 format; + -issuerKeystorePwd : issuer keystore password, optional fields; + + EXAMPLE: + generate-profile-cert -keyAlias "oh-profile-key-v1" -issuerKeyAlias "oh-profile-sign-debug-srv-ca-key-v1" +-keyPwd ****** -issuerKeyPwd ****** -keystoreFile "/home/profile-keypair.jks" -keystorePwd ****** -validity 365 +-issuer "C=CN, O=OpenHarmony, OU=OpenHarmony Community, CN=Provision Profile Debug Signature Service CA" +-subject "C=CN, O=OpenHarmony, OU=OpenHarmony Community, CN=Provision Profile Debug" -signAlg SHA256withECDSA +-outFile "/home/provision-profile-debug.cer" -outForm cert + generate-profile-cert -keyAlias "oh-profile-key-v1" -issuerKeyAlias "oh-profile-sign-release-srv-ca-key-v1" +-keyPwd ****** -issuerKeyPwd ****** -keystoreFile "/home/profile-keypair.jks" -keystorePwd ****** -validity 365 +-issuer "C=CN, O=OpenHarmony, OU=OpenHarmony Community, CN=Provision Profile Release Signature Service CA" +-subject "C=CN, O=OpenHarmony, OU=OpenHarmony Community, CN=Provision Profile Release" -signAlg SHA256withECDSA +-rootCaCertFile "/home/root-ca.cer" -subCaCertFile "/home/sub-profile-sign-srv-ca.cer" -outForm certChain +-outFile "/home/provision-profile-release.cer" +)"; + + +const std::string SIGN_PROFILE_HELP_TXT = R"( + sign-profile[options]: + -mode : signature mode, required fields, including localSign/remoteSign; + -keyAlias : key alias, required fields; + -keyPwd : key password, optional fields; + -profileCertFile : profile signing certificate(certificate chain, the order is three -level -two -root), + required fields; + -inFile : input original Provision Profile file, required fields; + -signAlg : signature algorithm, required fields, including SHA256withECDSA/SHA384withECDSA; + -keystoreFile : keystore file, if signature mode is localSign, required fields, JKS or P12 format; + -keystorePwd : keystore password, optional fields; + -outFile : output the signed Provision Profile file, p7b format, required fields; + -extCfgFile : Extend Profile, optional fields; + -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; + + EXAMPLE: + sign-profile -mode localSign -keyAlias "oh-profile-key-v1" -outFile "/home/signed-profile.p7b" +-keystoreFile "/home/profile-keypair.jks" -keystorePwd ****** -keyPwd ****** -signAlg SHA256withECDSA +-profileCertFile "/home/provision-profile-release.cer" -inFile "/home/app1-profile-release.json" +)"; + +const std::string VERIFY_PROFILE_HELP_TXT = R"( + verify-profile[options]: + -inFile : signed Provision Profile file, p7b format, required fields; + -outFile : Verification result file(including verification result and profile content), + json format, optional; if not filled, it will be directly output to the console; + -extCfgFile : Extend Profile, optional fields; + + EXAMPLE: + verify-profile -inFile "/home/signed-profile.p7b" -outFile "/home/VerifyResult.json" +)"; + +const std::string SIGN_APP_HELP_TXT = R"( + sign-app[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; + -extCfgFile : Extend Profile, optional fields; + -inForm : Enter the format of the original file.The supported file formats include.zip, .bin, and .elf.; + -compatibleVersion : min compatible api version for running app, required fields while input original + 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. + + EXAMPLE : + sign-app-mode localSign -keyAlias "oh-app1-key-v1" -appCertFile "/home/app-release-cert.cer" -signCode "1" +-keystoreFile "/home/app-keypair.jks" -keystorePwd ****** -outFile "/home/app1-signed.hap -compatibleVersion 8" +-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; + -extCfgFile : Extend Profile, optional fields; + -inForm : Enter the format of the original file.The supported file formats include.zip, .bin, and .elf.; + + EXAMPLE: + verify-app-inFile "/home/app1-signed.hap" -outCertChain "outCertChain.cer" -outProfile "outprofile.p7b" +)"; + +const std::string HELP_END_TXT = R"( +COMMANDS : + generate-keypair : generate key pair + generate-csr : generate certificate signing request + generate-cert : generate certificate in full, large and complete, any certificate can be generated + generate-ca : generate root / subject CA certificate, if the key does not exist, generate the key together + generate-app -cert : generate application debug / release certificate + generate-profile -cert : generate application debug / release certificate + sign-profile : Provision Profile file signature + verify-profile : Provision Profile file verification + sign-app : application package signature + verify-app : application package file verification +)"; +/* help.txt all content */ +const std::string HELP_TXT = HELP_TXT_HEADER + KEYPAIR_HELP_TXT + CSR_HELP_TXT + CERT_HELP_TXT ++ CA_CERT_HELP_TXT + APP_CERT_HELP_TXT + PROFILE_CERT_HELP_TXT ++ SIGN_PROFILE_HELP_TXT + VERIFY_PROFILE_HELP_TXT + SIGN_APP_HELP_TXT ++ VERIFY_APP_HELP_TXT + HELP_END_TXT; +} +} +#endif \ No newline at end of file diff --git a/hapsigntool_cpp/cmd/include/options.h b/hapsigntool_cpp/cmd/include/options.h new file mode 100644 index 0000000000000000000000000000000000000000..f217a61257bc4ffa62ddf3047b1397cfa2f30087 --- /dev/null +++ b/hapsigntool_cpp/cmd/include/options.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2024-2024 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, std::string checkStr); + int GetInt(const std::string key); + bool Equals(const std::string key1, const std::string& key2); + bool Required(const std::initializer_list keys); + bool IsEmpty(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; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_OPTIONS_H diff --git a/hapsigntool_cpp/cmd/include/params.h b/hapsigntool_cpp/cmd/include/params.h new file mode 100644 index 0000000000000000000000000000000000000000..192dd538f6d2b7d31a46771d835859d11784fcd9 --- /dev/null +++ b/hapsigntool_cpp/cmd/include/params.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024-2024 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() = default; + virtual ~Params() = default; + virtual std::string GetMethod(); + virtual void SetMethod(const std::string& method); + virtual Options* GetOptions(); + +private: + std::shared_ptr options = std::make_shared(); + +private: + std::string method; +}; + +using ParamsSharedPtr = std::shared_ptr; + +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_PARAMS_H diff --git a/hapsigntool_cpp/cmd/include/params_run_tool.h b/hapsigntool_cpp/cmd/include/params_run_tool.h new file mode 100644 index 0000000000000000000000000000000000000000..b84597828cb0539e6589d4a9f3c8424c05a09e16 --- /dev/null +++ b/hapsigntool_cpp/cmd/include/params_run_tool.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024-2024 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(ParamsSharedPtr params, SignToolServiceImpl& api); + static bool CallGenerators(ParamsSharedPtr params, SignToolServiceImpl& api); + static bool RunKeypair(Options* params, SignToolServiceImpl& api); + static bool RunCa(Options* params, SignToolServiceImpl& api); + static bool RunCert(Options* params, SignToolServiceImpl& api); + static bool RunAppCert(Options* params, SignToolServiceImpl& api); + static bool RunProfileCert(Options* params, SignToolServiceImpl& api); + static bool RunCsr(Options* params, SignToolServiceImpl& api); + static bool RunSignProfile(Options* params, SignToolServiceImpl& api); + static bool RunSignApp(Options* params, SignToolServiceImpl& api); + static bool RunVerifyProfile(Options* params, SignToolServiceImpl& api); + static bool RunVerifyApp(Options* params, SignToolServiceImpl& api); + static bool CheckEndCertArguments(Options& params); + static bool CheckProfile(Options& params); + static void PrintHelp(); + static void Version(); + +public: + static std::vector InformList; + +private: + static const std::string VERSION; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_HAP_SIGN_TOOL_H diff --git a/hapsigntool_cpp/cmd/include/params_trust_list.h b/hapsigntool_cpp/cmd/include/params_trust_list.h new file mode 100644 index 0000000000000000000000000000000000000000..8d3da08c5dd21f72a875be74fa46e5a305cf7b87 --- /dev/null +++ b/hapsigntool_cpp/cmd/include/params_trust_list.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024-2024 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" +#include "hap_verify_result.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: + static std::unique_ptr paramTrustListInstance; + static std::mutex mtx; + std::unordered_map> trustMap; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif diff --git a/hapsigntool_cpp/cmd/signature_tools_cmd.gni b/hapsigntool_cpp/cmd/signature_tools_cmd.gni new file mode 100644 index 0000000000000000000000000000000000000000..16fdb14a45599b8325cf5db3bc619327aaf59f83 --- /dev/null +++ b/hapsigntool_cpp/cmd/signature_tools_cmd.gni @@ -0,0 +1,23 @@ +# Copyright (c) 2024 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/options.cpp", + "${signature_tools_cmd}/src/params_trust_list.cpp", + "${signature_tools_cmd}/src/params.cpp", +] diff --git a/hapsigntool_cpp/cmd/src/cmd_util.cpp b/hapsigntool_cpp/cmd/src/cmd_util.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e17b973f541acfee7f1e5149134409f87a1083af --- /dev/null +++ b/hapsigntool_cpp/cmd/src/cmd_util.cpp @@ -0,0 +1,531 @@ +/* + * Copyright (c) 2024-2024 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(ParamsSharedPtr param) +{ + int defualtValidity = 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; + } + } + try { + validity = stoi(val); + } + catch (std::exception& e) { + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, "Invalid parameter '" + + val + "', You should fill in the numbers"); + 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) { + defualtValidity = DEFAULT_VALIDITY_DAYS * ONE_DAY_TIME; + (*options)[Options::VALIDITY] = defualtValidity; + } else if (param->GetMethod() == GENERATE_CERT) { + defualtValidity = DEFAULT_CUSTOM_VALIDITY_DAYS * ONE_DAY_TIME; + (*options)[Options::VALIDITY] = defualtValidity; + } + return true; +} + +static bool UpdateParamForVariantInt(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); + try { + basicConstraintsPathLen = stoi(val); + } + catch (std::exception& e) { + 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(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 UpdateParamForVariantBoolConstraints(ParamsSharedPtr param) +{ + Options* options = param->GetOptions(); + + //The bool type is used only by the "generate-cert" module + if (options->count(Options::BASIC_CONSTRAINTS)) { + if (!CmdUtil::String2Bool(options, Options::BASIC_CONSTRAINTS)) { + return false; + } + } else if (param->GetMethod() == GENERATE_CERT) { + (*options)[Options::BASIC_CONSTRAINTS] = DEFAULT_BASIC_CONSTRAINTS; + } + + //The bool type is used only by the "generate-cert" module + if (options->count(Options::BASIC_CONSTRAINTS_CRITICAL)) { + if (!CmdUtil::String2Bool(options, Options::BASIC_CONSTRAINTS_CRITICAL)) { + return false; + } + } else if (param->GetMethod() == GENERATE_CERT) { + (*options)[Options::BASIC_CONSTRAINTS_CRITICAL] = DEFAULT_BASIC_CONSTRAINTS_CRITICAL; + } + return true; +} + +static bool UpdateParamForVariantBoolProfileSigned(ParamsSharedPtr param) +{ + Options* options = param->GetOptions(); + + //The bool type is used only by the "sign-app" 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_APP) { + (*options)[Options::PROFILE_SIGNED] = DEFAULT_PROFILE_SIGNED_1; + } + + //The bool type is used only by the "generate-cert" module + if (options->count(Options::BASIC_CONSTRAINTS_CA)) { + if (!CmdUtil::String2Bool(options, Options::BASIC_CONSTRAINTS_CA)) { + return false; + } + } else if (param->GetMethod() == GENERATE_CERT) { + (*options)[Options::BASIC_CONSTRAINTS_CA] = DEFAULT_BASIC_CONSTRAINTS_CA; + } + return true; +} + +static bool outFilePath(Options* options) +{ + std::initializer_list outFileKeys = { + Options::OUT_FILE, Options::KEY_STORE_FILE, + Options::ISSUER_KEY_STORE_FILE, + Options::OUT_PROFILE, Options::OUT_CERT_CHAIN}; + + // check path directory is exists + for (auto& key : outFileKeys) { + if (options->count(key)) { + std::filesystem::path pat = options->GetString(key); + if (std::filesystem::is_directory(pat)) { + PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "'" + std::string(pat.c_str()) + + "' is a directory"); + return false; + } + std::string parentPath = pat.parent_path(); + if (!std::filesystem::exists(parentPath)) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "output file parent directory'" + + std::string(parentPath.c_str()) + "' not exist"); + return false; + } + } + } + return true; +} + +static bool UpdateParamForCheckFile(ParamsSharedPtr param) +{ + // check file exists + Options* options = param->GetOptions(); + std::initializer_list inFileKeys = { + Options::IN_FILE, + Options::SUB_CA_CERT_FILE, + Options::CA_CERT_FILE, + Options::PROFILE_CERT_FILE, + Options::APP_CERT_FILE, + Options::PROFILE_FILE}; + for (auto& key : inFileKeys) { + if (options->count(key) && + !FileUtils::IsValidFile(options->GetString(key))) { + return false; + } + } + // check path exists + if (!outFilePath(options)) { + return false; + } + return true; +} + +static bool UpdateParamForCheckSignAlg(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("COMMAND_ERROR", COMMAND_ERROR, "'" + signAlg + "' parameter is incorrect"); + return false; + } + } + return true; +} + +static bool UpdateParamForInform(ParamsSharedPtr param) +{ + // check sign_app verify_app inform + Options* options = param->GetOptions(); + if (param->GetMethod() == SIGN_APP || + param->GetMethod() == VERIFY_APP) { + if (options->count(Options::INFORM)) { + std::string inForm = options->GetString(Options::INFORM); + if (!StringUtils::ContainsCase(ParamsRunTool::InformList, inForm)) { + PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "parameter '" + inForm + + "' format error, Inform only support zip/elf/bin"); + return false; + } + } else { + (*options)[Options::INFORM] = ZIP; + } + } + return true; +} + +static bool UpdateParamForOutform(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(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(ParamsSharedPtr param) +{ + if (!UpdateParamForVariantInt(param)) { + return false; + } + if (!UpdateParamForVariantBoolKeyUsage(param)) { + return false; + } + if (!UpdateParamForVariantBoolConstraints(param)) { + return false; + } + if (!UpdateParamForVariantBoolProfileSigned(param)) { + return false; + } + if (!UpdateParamForCheckFile(param)) { + return false; + } + if (!UpdateParamForCheckSignAlg(param)) { + return false; + } + if (!UpdateParamForInform(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, 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; + } + } + } + if (!readKey) { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, + "The last command-line parameters, value, cannot be omitted"); + return false; + } + if (!UpdateParam(param)) { + return false; + } + return true; +} + +bool CmdUtil::ValidAndPutParam(ParamsSharedPtr params, const std::string& key, char* value) +{ + std::string str = "Pwd"; + bool result; + 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); + result = true; + } else { + params->GetOptions()->emplace(key, std::string(value)); + result = true; + } + return result; +} + +bool CmdUtil::JudgeAlgType(const std::string& keyAlg) +{ + if (keyAlg != "ECC") { + PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "not supported '" + keyAlg + "' Key algorithms"); + return false; + } + return true; +} + +bool CmdUtil::JudgeSize(const int size) +{ + if (size != NIST_P_256 && size != NIST_P_384) { + PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "Keysize params is incorrect, Support only 256 or 384"); + return false; + } + return true; +} + +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; +} + +/** + * @tc.name: Test parameter function + * @tc.desc: Pass more than one parameter,but it needs to be in the parameter list. + * @tc.type: FUNC + */ +bool CmdUtil::VerifyTypes(const std::string& inputType) +{ + if (inputType.size() == 0) { + return false; + } + std::vector vecs = StringUtils::SplitString(inputType.c_str(), ','); + std::set sets; + sets.insert("digitalSignature"); + sets.insert("nonRepudiation"); + sets.insert("keyEncipherment"); + sets.insert("dataEncipherment"); + sets.insert("keyAgreement"); + sets.insert("certificateSignature"); + sets.insert("crlSignature"); + sets.insert("encipherOnly"); + sets.insert("decipherOnly"); + for (const auto& val : vecs) { + if (sets.count(val) == 0) { + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, + "Not support command param '" + val + "'"); + return false; + } + } + return true; +} + +/** + * @tc.name: Test parameter function + * @tc.desc: Pass one parameter,but it needs to be in the parameter list. + * @tc.type: FUNC + */ +bool CmdUtil::VerifyType(const std::string& inputType) +{ + std::set sets; + sets.insert("clientAuthentication"); + sets.insert("serverAuthentication"); + sets.insert("codeSignature"); + sets.insert("emailProtection"); + sets.insert("smartCardLogin"); + sets.insert("timestamp"); + sets.insert("ocspSignature"); + if (sets.count(inputType) == 0) { + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, + "Not support command param '" + inputType + "'"); + return false; + } + return true; +} + +bool CmdUtil::VerifyType(const std::string& inputtype, const std::string& supportTypes) +{ + std::string firstStr = supportTypes.substr(0, supportTypes.find_last_of(",")); + std::string secondStr = supportTypes.substr(supportTypes.find_first_of(",") + 1, + supportTypes.size() - supportTypes.find_first_of(",")); + if (inputtype == firstStr || inputtype == secondStr) { + return true; + } + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, "Not support command param '" + inputtype + "'"); + + return false; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/cmd/src/options.cpp b/hapsigntool_cpp/cmd/src/options.cpp new file mode 100644 index 0000000000000000000000000000000000000000..24a98b6df8d3819cb48383f8098049ac33ceb52b --- /dev/null +++ b/hapsigntool_cpp/cmd/src/options.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2024-2024 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"; + +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, 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 key1, const std::string& key2) +{ + std::string ksFile = GetString(key1); + std::string iksFile = GetString(key2); + 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(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/hapsigntool_cpp/cmd/src/params.cpp b/hapsigntool_cpp/cmd/src/params.cpp new file mode 100644 index 0000000000000000000000000000000000000000..81819176cb811c6223728ada56808d47326e3df3 --- /dev/null +++ b/hapsigntool_cpp/cmd/src/params.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024-2024 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 { +std::string Params::GetMethod() +{ + return method; +} + +void Params::SetMethod(const std::string& method) +{ + this->method = method; +} + +Options* Params::GetOptions() +{ + return options.get(); +} + +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/hapsigntool_cpp/cmd/src/params_run_tool.cpp b/hapsigntool_cpp/cmd/src/params_run_tool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2d161a61f6ef9da56f154046b42b1a3d906160f6 --- /dev/null +++ b/hapsigntool_cpp/cmd/src/params_run_tool.cpp @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2024-2024 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"; + +std::vector ParamsRunTool::InformList = { + "bin", + "elf", + "zip" +}; + +static std::unordered_map > DISPATCH_RUN_METHOD { + {SIGN_APP, ParamsRunTool::RunSignApp}, + {SIGN_PROFILE, ParamsRunTool::RunSignProfile}, + {VERIFY_APP, ParamsRunTool::RunVerifyApp}, + {VERIFY_PROFILE, ParamsRunTool::RunVerifyProfile} +}; + +static std::unordered_map > GENERATOR_RUN_METHOD { + {GENERATE_KEYPAIR, ParamsRunTool::RunKeypair}, + {GENERATE_CSR, ParamsRunTool::RunCsr}, + {GENERATE_CA, ParamsRunTool::RunCa}, + {GENERATE_APP_CERT, ParamsRunTool::RunAppCert}, + {GENERATE_PROFILE_CERT, ParamsRunTool::RunProfileCert}, + {GENERATE_CERT, ParamsRunTool::RunCert}, +}; + + +bool ParamsRunTool::ProcessCmd(char** args, size_t size) +{ + if (size < CmdUtil::ARGS_MIN_LEN) { + args[1] = const_cast(""); + } + 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.get())) { + 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::CallGenerators(ParamsSharedPtr params, SignToolServiceImpl& api) +{ + bool isSuccess = false; + std::string method = params->GetMethod(); + if (GENERATOR_RUN_METHOD.count(method) == 0) { + PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "Unsupported method: " + method); + return false; + } else { + isSuccess=GENERATOR_RUN_METHOD[method](params->GetOptions(), api); + } + return isSuccess; +} + +bool ParamsRunTool::RunSignApp(Options* params, SignToolServiceImpl& api) +{ + if (!params->Required({Options::MODE, Options::IN_FILE, Options::OUT_FILE, Options::SIGN_ALG})) { + return false; + } + 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 inForm = params->GetString(Options::INFORM, ZIP); + if (!StringUtils::IsEmpty(inForm) && !StringUtils::ContainsCase(InformList, inForm)) { + PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "parameter '" + inForm + + "' format error, Inform only support zip/elf/bin"); + return false; + } + std::string signAlg = params->GetString(Options::SIGN_ALG); + if (!CmdUtil::JudgeSignAlgType(signAlg)) { + return false; + } + return api.SignHap(params); +} + +bool ParamsRunTool::CheckProfile(Options& params) +{ + std::string inForm = params.GetString(Options::INFORM); + std::string profileFile = params.GetString(Options::PROFILE_FILE); + + std::string profileSigned = params.GetString(Options::PROFILE_SIGNED); + if (StringUtils::CaseCompare(inForm, ELF) && FileUtils::IsEmpty(profileFile)) { + return true; + } + + if (profileSigned == "1") { + if (!FileUtils::ValidFileType(profileFile, {"p7b"})) { + return false; + } + } else { + if (!FileUtils::ValidFileType(profileFile, {"json"})) { + return false; + } + } + + return true; +} + +bool ParamsRunTool::DispatchParams(ParamsSharedPtr params, SignToolServiceImpl& api) +{ + bool isSuccess = false; + std::string method = params->GetMethod(); + if (DISPATCH_RUN_METHOD.count(method) == 0) { + isSuccess = ParamsRunTool::CallGenerators(params, api); + } else { + isSuccess = DISPATCH_RUN_METHOD[method](params->GetOptions(), api); + } + return isSuccess; +} + +bool ParamsRunTool::RunCa(Options* params, SignToolServiceImpl& api) +{ + if (!params->Required({Options::KEY_ALIAS, Options::KEY_ALG, + Options::KEY_SIZE, Options::SUBJECT, Options::SIGN_ALG, Options::KEY_STORE_FILE})) { + return false; + } + std::string keyAlg = params->GetString(Options::KEY_ALG); + if (!CmdUtil::JudgeAlgType(keyAlg)) { + return false; + } + int size = params->GetInt(Options::KEY_SIZE); + if (!CmdUtil::JudgeSize(size)) { + return false; + } + std::string signAlg = params->GetString(Options::SIGN_ALG); + if (!CmdUtil::JudgeSignAlgType(signAlg)) { + return false; + } + if (!FileUtils::ValidFileType(params->GetString(Options::KEY_STORE_FILE), {"p12", "jks"})) { + return false; + } + + return api.GenerateCA(params); +} + +bool ParamsRunTool::RunCert(Options* params, SignToolServiceImpl& api) +{ + if (!params->Required({Options::KEY_ALIAS, Options::ISSUER, + Options::ISSUER_KEY_ALIAS, Options::SUBJECT, Options::KEY_USAGE, + Options::SIGN_ALG, Options::KEY_STORE_FILE})) { + return false; + } + std::string keyusage = params->GetString(Options::KEY_USAGE); + if (!CmdUtil::VerifyTypes(keyusage)) { + return false; + } + std::string extkeyusage = params->GetString(Options::EXT_KEY_USAGE); + if (!extkeyusage.empty()) { + if (!CmdUtil::VerifyType(extkeyusage)) { + return false; + } + } + std::string signAlg = params->GetString(Options::SIGN_ALG); + if (!CmdUtil::JudgeSignAlgType(signAlg)) { + return false; + } + if (!FileUtils::ValidFileType(params->GetString(Options::KEY_STORE_FILE), {"p12", "jks"})) { + return false; + } + return api.GenerateCert(params); +} + +bool ParamsRunTool::CheckEndCertArguments(Options& params) +{ + if (!params.Required({params.KEY_ALIAS, params.ISSUER, params.ISSUER_KEY_ALIAS, + params.SUBJECT, params.SIGN_ALG, params.KEY_STORE_FILE})) { + return false; + } + std::string signAlg = params.GetString(params.SIGN_ALG); + if (!CmdUtil::JudgeSignAlgType(signAlg)) { + return false; + } + std::string outForm = params.GetString(params.OUT_FORM); + if (!outForm.empty()) { + if (!CmdUtil::VerifyType(outForm, Options::OUT_FORM_SCOPE)) { + return false; + } + } + if (!outForm.empty() && "certChain" == outForm) { + if (!params.Required({params.SUB_CA_CERT_FILE, params.CA_CERT_FILE})) { + return false; + } + if (!FileUtils::ValidFileType(params.GetString(params.SUB_CA_CERT_FILE), {"cer"}) || + !FileUtils::ValidFileType(params.GetString(params.CA_CERT_FILE), {"cer"})) { + return false; + } + } + std::string keyStoreFile = params.GetString(params.KEY_STORE_FILE); + if (!FileUtils::ValidFileType(keyStoreFile, {"p12", "jks"})) { + return false; + } + if (params.find(params.ISSUER_KEY_STORE_FILE) != params.end()) { + std::string issuerKeyStoreFile = params.GetString(params.ISSUER_KEY_STORE_FILE); + if (!FileUtils::ValidFileType(issuerKeyStoreFile, {"p12", "jks"})) { + return false; + } + } + std::string outFile = params.GetString(params.OUT_FILE); + if (!outFile.empty()) { + if (!FileUtils::ValidFileType(outFile, {"cer", "pem"})) { + return false; + } + } + return true; +} + +bool ParamsRunTool::RunAppCert(Options* params, SignToolServiceImpl& api) +{ + if (!ParamsRunTool::CheckEndCertArguments(*params)) { + return false; + } + return api.GenerateAppCert(params); +} + +bool ParamsRunTool::RunProfileCert(Options* params, SignToolServiceImpl& api) +{ + if (!ParamsRunTool::CheckEndCertArguments(*params)) { + return false; + } + return api.GenerateProfileCert(params); +} + +bool ParamsRunTool::RunKeypair(Options* params, SignToolServiceImpl& api) +{ + if (!params->Required({Options::KEY_ALIAS, Options::KEY_ALG, Options::KEY_SIZE, Options::KEY_STORE_FILE})) { + return false; + } + std::string keyAlg = params->GetString(Options::KEY_ALG); + if (!CmdUtil::JudgeAlgType(keyAlg)) { + return false; + } + int size = params->GetInt(Options::KEY_SIZE); + if (!CmdUtil::JudgeSize(size)) { + return false; + } + if (!FileUtils::ValidFileType(params->GetString(Options::KEY_STORE_FILE), {"p12", "jks"})) { + return false; + } + return api.GenerateKeyStore(params); +} + +bool ParamsRunTool::RunCsr(Options* params, SignToolServiceImpl& api) +{ + if (!params->Required({Options::KEY_ALIAS, Options::SUBJECT, Options::SIGN_ALG, Options::KEY_STORE_FILE})) { + return false; + } + std::string signAlg = params->GetString(Options::SIGN_ALG); + if (!CmdUtil::JudgeSignAlgType(signAlg)) { + return false; + } + if (!FileUtils::ValidFileType(params->GetString(Options::KEY_STORE_FILE), {"p12", "jks"})) { + return false; + } + if (params->count(Options::OUT_FILE)) { + if (!FileUtils::ValidFileType(params->GetString(Options::OUT_FILE), {"csr"})) { + return false; + } + } + return api.GenerateCsr(params); +} + +bool ParamsRunTool::RunSignProfile(Options* params, SignToolServiceImpl& api) +{ + if (!params->Required({params->MODE, params->SIGN_ALG, params->OUT_FILE, params->IN_FILE})) { + return false; + } + 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({params->KEY_STORE_FILE, params->KEY_ALIAS, params->PROFILE_CERT_FILE})) { + return false; + } + + if (!FileUtils::ValidFileType(params->GetString(Options::KEY_STORE_FILE), {"p12", "jks"})) { + return false; + } + } + std::string signAlg = params->GetString(Options::SIGN_ALG); + if (!CmdUtil::JudgeSignAlgType(signAlg)) { + return false; + } + std::string outFile = params->GetString(Options::OUT_FILE); + if (FileUtils::ValidFileType(outFile, {"p7b"}) == false) { + return false; + } + return api.SignProfile(params); +} + +bool ParamsRunTool::RunVerifyProfile(Options* params, SignToolServiceImpl& api) +{ + if (!params->Required({Options::IN_FILE})) { + return false; + } + + if (!FileUtils::ValidFileType(params->GetString(Options::IN_FILE), {"p7b"})) { + return false; + } + + std::string outFile = params->GetString(Options::OUT_FILE); + if (!outFile.empty()) { + if (!FileUtils::ValidFileType(outFile, {"json"})) { + return false; + } + } + return api.VerifyProfile(params); +} + +void ParamsRunTool::PrintHelp() +{ + PrintMsg(HELP_TXT); +} + +void ParamsRunTool::Version() +{ + PrintMsg(ParamsRunTool::VERSION); +} + +bool ParamsRunTool::RunVerifyApp(Options* params, SignToolServiceImpl& api) +{ + if (!params->Required({Options::IN_FILE, Options::OUT_CERT_CHAIN, Options::OUT_PROFILE})) { + return false; + } + std::string inForm = params->GetString(Options::INFORM, ZIP); + if (!StringUtils::ContainsCase(InformList, inForm)) { + PrintErrorNumberMsg("COMMAND_ERROR", COMMAND_ERROR, "parameter '" + inForm + + "' format error, Inform only support zip/elf/bin"); + return false; + } + if (!FileUtils::ValidFileType(params->GetString(Options::OUT_CERT_CHAIN), {"cer"})) { + return false; + } + if (!FileUtils::ValidFileType(params->GetString(Options::OUT_PROFILE), {"p7b"})) { + return false; + } + return api.VerifyHapSigner(params); +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/cmd/src/params_trust_list.cpp b/hapsigntool_cpp/cmd/src/params_trust_list.cpp new file mode 100644 index 0000000000000000000000000000000000000000..28ce5177e64eb9e0175bc2b39f5a64b2744cee90 --- /dev/null +++ b/hapsigntool_cpp/cmd/src/params_trust_list.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2024-2024 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 "constant.h" +#include "params.h" +#include "string_utils.h" +#include "help.h" + +namespace OHOS { +namespace SignatureTools { +const std::string options = "[options]:"; +std::unique_ptr ParamsTrustList::paramTrustListInstance = nullptr; +std::mutex ParamsTrustList::mtx; + +const std::vector commands = { + GENERATE_KEYPAIR + options, + GENERATE_CSR + options, + GENERATE_CERT + options, + GENERATE_CA + options, + GENERATE_APP_CERT + options, + GENERATE_PROFILE_CERT + options, + SIGN_PROFILE + options, + VERIFY_PROFILE + options, + SIGN_APP + options, + VERIFY_APP + options +}; + +ParamsTrustList* ParamsTrustList::GetInstance() +{ + if (!paramTrustListInstance) { + std::lock_guard lock(mtx); + if (!paramTrustListInstance) { + paramTrustListInstance = std::make_unique(); + } + } + + return paramTrustListInstance.get(); +} + +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; + } + for (const auto& it : commands) { + if (it == params) { + cmdStandBy = params; + isExists = true; + break; + } + } + if (!isExists) { + 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/hapsigntool_cpp/codesigning/datastructure/include/code_sign_block.h b/hapsigntool_cpp/codesigning/datastructure/include/code_sign_block.h new file mode 100644 index 0000000000000000000000000000000000000000..b02481498a2267f32c763c5fe5b30f83711e4843 --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/include/code_sign_block.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024-2024 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_CODE_SIGN_BLOCK_H +#define SIGNATRUETOOLS_CODE_SIGN_BLOCK_H + +#include +#include +#include +#include + +#include "segment_header.h" +#include "hap_info_segment.h" +#include "code_sign_block_header.h" +#include "fs_verity_info_segment.h" +#include "native_lib_info_segment.h" + +namespace OHOS { +namespace SignatureTools { + +class CodeSignBlock { +public: + static constexpr long PAGE_SIZE_4K = 4096; + static constexpr int SEGMENT_HEADER_COUNT = 3; + CodeSignBlock(); + virtual ~CodeSignBlock(); + void AddOneMerkleTree(const std::string& key, std::vector& merkleTree); + std::vector GetOneMerkleTreeByFileName(const std::string& key); + void SetCodeSignBlockFlag(); + void SetSegmentNum(); + void AddToSegmentList(SegmentHeader sh); + std::vector& GetSegmentHeaderList(); + void SetSegmentHeaders(); + CodeSignBlockHeader& GetCodeSignBlockHeader(); + void SetCodeSignBlockHeader(CodeSignBlockHeader& csbHeader); + void SetFsVerityInfoSegment(FsVerityInfoSegment& fsVeritySeg); + HapInfoSegment& GetHapInfoSegment(); + void SetHapInfoSegment(HapInfoSegment& hapSeg); + NativeLibInfoSegment& GetSoInfoSegment(); + void SetSoInfoSegment(NativeLibInfoSegment soSeg); + void ToByteArray(std::vector& ret); + void ComputeSegmentOffset(); + int64_t ComputeMerkleTreeOffset(int64_t codeSignBlockOffset); + void GenerateCodeSignBlockByte(int64_t fsvTreeOffset, std::vector& ret); + +private: + CodeSignBlockHeader codeSignBlockHeader; + std::vector segmentHeaderList; + FsVerityInfoSegment fsVerityInfoSegment; + HapInfoSegment hapInfoSegment; + NativeLibInfoSegment nativeLibInfoSegment; + std::vector zeroPadding; + std::map> merkleTreeMap; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_CODE_SIGN_BLOCK_H diff --git a/hapsigntool_cpp/codesigning/datastructure/include/code_sign_block_header.h b/hapsigntool_cpp/codesigning/datastructure/include/code_sign_block_header.h new file mode 100644 index 0000000000000000000000000000000000000000..75c0c7026f5443f5902e4506ca2c46740f9798a8 --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/include/code_sign_block_header.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2024-2024 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_CODE_SIGN_BLOCK_HEADER_H +#define SIGNATRUETOOLS_CODE_SIGN_BLOCK_HEADER_H + +#include +#include + +#include "byte_buffer.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { + +class CodeSignBlockHeader { +public: + class Builder { + public: + virtual CodeSignBlockHeader* Build(); + virtual ~Builder(); + + virtual Builder* SetMagic(int64_t magic); + virtual Builder* SetVersion(int version); + virtual Builder* SetBlockSize(int blockSize); + virtual Builder* SetSegmentNum(int segmentNum); + virtual Builder* SetFlags(int flags); + virtual Builder* SetReserved(std::vector& reserved); + + int64_t magic = MAGIC_NUM; + int version = CODE_SIGNING_VERSION; + int blockSize = 0; + int segmentNum = 0; + int flags = 0; + std::vector reserved = std::vector(RESERVED_BYTE_ARRAY_LENGTH); + }; + +public: + static const int FLAG_MERKLE_TREE_INLINED = 0x1; + static const int FLAG_NATIVE_LIB_INCLUDED = 0x2; + CodeSignBlockHeader(); + CodeSignBlockHeader(Builder* builder); + virtual ~CodeSignBlockHeader(); + static CodeSignBlockHeader* FromByteArray(std::vector& bytes); + static int Size(); + virtual void SetSegmentNum(int num); + virtual int GetSegmentNum(); + virtual void SetBlockSize(int64_t size); + virtual int GetBlockSize(); + virtual void SetFlags(int flags); + virtual void ToByteArray(std::vector& ret); + +private: + static const signed int MAGIC_BYTE_LENGTH = 4; + static constexpr int CODE_SIGNING_VERSION = 1; + // byte size of magic number + static const int8_t MAGIC_BYTE_ARRAY_LENGTH = 8; + // lower 8 bytes of MD5 result of string "hap code sign block" (E046 C8C6 5389 FCCD) + static const int64_t MAGIC_NUM = ((0xE046C8C6LL << 32) + 0x5389FCCDLL); + // size of byte[8] reserved + static const int8_t RESERVED_BYTE_ARRAY_LENGTH = 8; + // At all times three segment are always included in code sign block + // update this if new segments are created. + static const int SEGMENT_NUM = 3; + int64_t magic = 0; + int version = 0; + int blockSize = 0; + int segmentNum = 0; + // FLAG_MERKLE_TREE_INLINED + FLAG_NATIVE_LIB_INCLUDED + int flags = 0; + std::vector reserved; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_CODE_SIGN_BLOCK_HEADER_H diff --git a/hapsigntool_cpp/codesigning/datastructure/include/elf_sign_block.h b/hapsigntool_cpp/codesigning/datastructure/include/elf_sign_block.h new file mode 100644 index 0000000000000000000000000000000000000000..f2c44fb367ccdaaaaaa2873c515d96cf1ff93985 --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/include/elf_sign_block.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024-2024 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_ELF_SIGN_BLOCK_H +#define SIGNATRUETOOLS_ELF_SIGN_BLOCK_H + +#include +#include + +#include "fs_verity_descriptor_with_sign.h" + +namespace OHOS { +namespace SignatureTools { + +class ElfSignBlock { +public: + static constexpr int32_t PAGE_SIZE_4K = 4096; + static constexpr int32_t MERKLE_TREE_INLINED = 0x2; + +public: + ElfSignBlock(); + ElfSignBlock(int32_t paddingSize, std::vector &merkleTreeData, + FsVerityDescriptorWithSign &descriptorWithSign); + int32_t Size(); + std::vector& GetMerkleTreeWithPadding(); + int64_t GetDataSize(); + int64_t GetTreeOffset(); + std::vector GetSignature(); + void ToByteArray(std::vector& ret); + static bool FromByteArray(std::vector& bytes, ElfSignBlock& elfSignBlock); + static int32_t ComputeMerkleTreePaddingLength(int64_t signBlockOffset); + +private: + int32_t type = MERKLE_TREE_INLINED; + int32_t treeLength; + std::vector merkleTreeWithPadding; + FsVerityDescriptorWithSign descriptorWithSign; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_ELF_SIGN_BLOCK_H \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/datastructure/include/extension.h b/hapsigntool_cpp/codesigning/datastructure/include/extension.h new file mode 100644 index 0000000000000000000000000000000000000000..dccc90377204d72576af52c20a66d63498320801 --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/include/extension.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024-2024 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_EXTENSION_H +#define SIGNATRUETOOLS_EXTENSION_H + +#include +#include +#include + +#include "byte_buffer.h" + +namespace OHOS { +namespace SignatureTools { + +class Extension { +public: + static const int32_t EXTENSION_HEADER_SIZE; + Extension(); + Extension(int32_t type, int32_t size); + virtual ~Extension(); + virtual int32_t GetSize(); + virtual void ToByteArray(std::vector& ret); + bool IsType(int32_t type); + +private: + int32_t type; + int32_t size; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_EXTENSION_H diff --git a/hapsigntool_cpp/codesigning/datastructure/include/fs_verity_info_segment.h b/hapsigntool_cpp/codesigning/datastructure/include/fs_verity_info_segment.h new file mode 100644 index 0000000000000000000000000000000000000000..8c8ce50840d6ffc0d185481eceacf81c976b200e --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/include/fs_verity_info_segment.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024-2024 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_FS_VERITY_INFO_SEGMENT_H +#define SIGNATRUETOOLS_FS_VERITY_INFO_SEGMENT_H + +#include +#include + +#include "signature_tools_log.h" +#include "fs_verity_descriptor.h" +#include "fs_verity_generator.h" + +namespace OHOS { +namespace SignatureTools { + +class FsVerityInfoSegment { +public: + static constexpr int FS_VERITY_INFO_SEGMENT_SIZE = 64; + FsVerityInfoSegment(); + FsVerityInfoSegment(int8_t version, int8_t hashAlgorithm, int8_t log2BlockSize); + FsVerityInfoSegment(int magic, int8_t version, int8_t hashAlgorithm, + int8_t log2BlockSize, std::vector reserved); + virtual ~FsVerityInfoSegment(); + virtual int Size(); + virtual void ToByteArray(std::vector& ret); + static FsVerityInfoSegment FromByteArray(std::vector &bytes); + +private: + static constexpr int MAGIC = static_cast((0x1E38 << 16) + (0x31AB));; + static constexpr int RESERVED_BYTE_ARRAY_LENGTH = 57; + int magic = MAGIC; + int8_t hashAlgorithm = 0; + int8_t version = 0; + int8_t log2BlockSize = 0; + std::vector reserved; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_FS_VERITY_INFO_SEGMENT_H diff --git a/hapsigntool_cpp/codesigning/datastructure/include/hap_info_segment.h b/hapsigntool_cpp/codesigning/datastructure/include/hap_info_segment.h new file mode 100644 index 0000000000000000000000000000000000000000..09217224c50e246a184f9a2ccfceaf1ba9b0d7de --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/include/hap_info_segment.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024-2024 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_INFO_SEGMENT_H +#define SIGNATRUETOOLS_HAP_INFO_SEGMENT_H + +#include +#include +#include + +#include "sign_info.h" +#include "byte_buffer.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { + +class HapInfoSegment { +public: + HapInfoSegment(); + HapInfoSegment(int32_t magic, SignInfo signInfo); + void SetSignInfo(SignInfo signInfo); + SignInfo& GetSignInfo(); + int32_t GetSize(); + void ToByteArray(std::vector& ret); + static HapInfoSegment FromByteArray(std::vector bytes); + +private: + static const int32_t MAGIC_NUM_BYTES = 4; + static const int32_t MAGIC_NUM = (0xC1B5 << 16) + 0xCC66; + static const int32_t CHUNK_SIZE = 4096; + int32_t magic; + SignInfo signInfo; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_HAP_INFO_SEGMENT_H diff --git a/hapsigntool_cpp/codesigning/datastructure/include/merkle_tree_extension.h b/hapsigntool_cpp/codesigning/datastructure/include/merkle_tree_extension.h new file mode 100644 index 0000000000000000000000000000000000000000..fa7ce5d182ff35486327ab6b7ac9ff3d15d66e6b --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/include/merkle_tree_extension.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024-2024 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_MERKLE_TREE_EXTENSION_H +#define SIGNATRUETOOLS_MERKLE_TREE_EXTENSION_H + +#include +#include + +#include "extension.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { + +class MerkleTreeExtension : public Extension { +public: + static constexpr int32_t MERKLE_TREE_INLINED = 0x1; + static constexpr int32_t MERKLE_TREE_EXTENSION_DATA_SIZE = 80; + MerkleTreeExtension(); + MerkleTreeExtension(int64_t merkleTreeSize, int64_t merkleTreeOffset, std::vector rootHash); + virtual ~MerkleTreeExtension(); + static MerkleTreeExtension* FromByteArray(std::vector& bytes); + virtual int32_t GetSize(); + virtual void ToByteArray(std::vector& ret); + int64_t GetMerkleTreeSize(); + int64_t GetMerkleTreeOffset(); + void SetMerkleTreeOffset(int64_t offset); + +private: + static constexpr int32_t ROOT_HASH_SIZE = 64; + static constexpr int32_t PAGE_SIZE_4K = 4096; + int64_t merkleTreeSize; + int64_t merkleTreeOffset; + std::vector rootHash; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_MERKLE_TREE_EXTENSION_H diff --git a/hapsigntool_cpp/codesigning/datastructure/include/native_lib_info_segment.h b/hapsigntool_cpp/codesigning/datastructure/include/native_lib_info_segment.h new file mode 100644 index 0000000000000000000000000000000000000000..6ed61213a1bbe3cbb44a3a7f12d887b31617df1a --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/include/native_lib_info_segment.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024-2024 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_NATIVE_LIB_INFO_SEGMENT_H +#define SIGNATRUETOOLS_NATIVE_LIB_INFO_SEGMENT_H + +#include +#include + +#include "sign_info.h" +#include "signed_file_pos.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { + +class NativeLibInfoSegment { +public: + static const int32_t MAGIC_LENGTH_SECNUM_BYTES = 12; + static const int32_t SIGNED_FILE_POS_SIZE = 16; + static const int32_t MAGIC_NUM = (0x0ED2 << 16) + 0xE720; + static const int32_t ALIGNMENT_FOR_SIGNINFO = 4; + NativeLibInfoSegment(); + NativeLibInfoSegment(int32_t magic, + int32_t segmentSize, + int32_t sectionNum, + std::vector signedFilePosList, + std::vector fileNameList, + std::vector signInfoList, + std::vector zeroPadding); + static NativeLibInfoSegment FromByteArray(std::vector &bytes); + void SetSoInfoList(std::vector> &soInfoList); + int32_t GetSectionNum(); + std::vector GetFileNameList(); + std::vector GetSignInfoList(); + int32_t Size(); + void ToByteArray(std::vector &ret); + +private: + static bool CheckBuffer(ByteBuffer* bf, int32_t& inMagic, + int32_t& inSegmentSize, int32_t& inSectionNum); + void GenerateList(); + int32_t magic; + int32_t segmentSize; + int32_t sectionNum; + std::vector> soInfoList; + std::vector signedFilePosList; + std::vector fileNameList; + std::vector signInfoList; + std::vector zeroPadding; + int32_t fileNameListBlockSize; + int32_t signInfoListBlockSize; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_NATIVE_LIB_INFO_SEGMENT_H diff --git a/hapsigntool_cpp/codesigning/datastructure/include/segment_header.h b/hapsigntool_cpp/codesigning/datastructure/include/segment_header.h new file mode 100644 index 0000000000000000000000000000000000000000..149b1906cccad6ff4a20b5bc69f7699beb664c7b --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/include/segment_header.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024-2024 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_SEGMENT_HEADER_H +#define SIGNATRUETOOLS_SEGMENT_HEADER_H + +#include +#include + +#include "byte_buffer.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { + +class SegmentHeader { +public: + static const int32_t SEGMENT_HEADER_LENGTH = 12; + static const int32_t CSB_FSVERITY_INFO_SEG = 0x1; + static const int32_t CSB_HAP_META_SEG = 0x2; + static const int32_t CSB_NATIVE_LIB_INFO_SEG = 0x3; + SegmentHeader(); + SegmentHeader(int32_t type, int32_t segmentSize); + SegmentHeader(int32_t type, int32_t segmentOffset, + int32_t segmentSize); + static std::unique_ptr FromByteArray(std::vector bytes); + int32_t GetType(); + void SetSegmentOffset(int32_t offset); + int32_t GetSegmentOffset(); + int32_t GetSegmentSize(); + void ToByteArray(std::vector &ret); + +private: + int32_t type; + int32_t segmentOffset; + int32_t segmentSize; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_SEGMENT_HEADER_H \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/datastructure/include/sign_info.h b/hapsigntool_cpp/codesigning/datastructure/include/sign_info.h new file mode 100644 index 0000000000000000000000000000000000000000..eee3c20a8bb236708113b5187f23dfc677ced488 --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/include/sign_info.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024-2024 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_INFO_H +#define SIGNATRUETOOLS_SIGN_INFO_H + +#include +#include +#include +#include +#include + +#include "signature_tools_log.h" +#include "merkle_tree_extension.h" + +namespace OHOS { +namespace SignatureTools { + +class SignInfo { +public: + static constexpr int32_t FLAG_MERKLE_TREE_INCLUDED = 0x1; + static constexpr int32_t MAX_EXTENSION_NUM = 1; + static constexpr int32_t SIGN_INFO_SIZE_WITHOUT_SIGNATURE = 60; + static constexpr int32_t SALT_BUFFER_LENGTH = 32; + static constexpr int32_t SIGNATURE_ALIGNMENT = 4; + SignInfo(); + SignInfo(int32_t saltSize, int32_t flags, int64_t dataSize, + std::vector &salt, std::vector &sig); + SignInfo(int32_t saltSize, + int32_t sigSize, + int32_t flags, + int64_t dataSize, + std::vector &salt, + int32_t extensionNum, + int32_t extensionOffset, + std::vector &signature, + std::vector &zeroPadding, + std::vector extensionList); + SignInfo(const SignInfo& other); + SignInfo& operator=(const SignInfo& other); + virtual ~SignInfo(); + static std::vector ParseMerkleTreeExtension(ByteBuffer* bf, int32_t inExtensionNum); + static SignInfo FromByteArray(std::vector bytes); + int32_t GetSize(); + void AddExtension(MerkleTreeExtension* extension); + Extension* GetExtensionByType(int32_t type); + int32_t GetExtensionNum(); + std::vector GetSignature(); + int64_t GetDataSize(); + void ToByteArray(std::vector &ret); + +private: + int32_t saltSize; + int32_t sigSize; + int32_t flags; + int64_t dataSize; + std::vector salt; + int32_t extensionNum; + int32_t extensionOffset; + std::vector signature; + std::vector zeroPadding; + std::vector extensionList; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_ELF_SIGN_BLOCK_H \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/datastructure/include/signed_file_pos.h b/hapsigntool_cpp/codesigning/datastructure/include/signed_file_pos.h new file mode 100644 index 0000000000000000000000000000000000000000..faa254067588e89ae612923935f137e28d60af8e --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/include/signed_file_pos.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024-2024 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_SIGNED_FILE_POS_H +#define SIGNATRUETOOLS_SIGNED_FILE_POS_H + +#include +#include +#include +#include + +#include "byte_buffer.h" + +namespace OHOS { +namespace SignatureTools { + +class SignedFilePos { +public: + SignedFilePos(int32_t fileNameOffset, + int32_t fileNameSize, + int32_t signInfoOffset, + int32_t signInfoSize); + static SignedFilePos FromByteArray(std::vector &bytes); + int32_t GetFileNameOffset(); + int32_t GetFileNameSize(); + int32_t GetSignInfoOffset(); + int32_t GetSignInfoSize(); + void IncreaseFileNameOffset(int32_t incOffset); + void IncreaseSignInfoOffset(int32_t incOffset); + +private: + int32_t fileNameOffset; + int32_t fileNameSize; + int32_t signInfoOffset; + int32_t signInfoSize; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_SIGNED_FILE_POS_H \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/datastructure/include/unzip_handle_param.h b/hapsigntool_cpp/codesigning/datastructure/include/unzip_handle_param.h new file mode 100644 index 0000000000000000000000000000000000000000..949fef973f6641136e638c0354341c0595addcf7 --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/include/unzip_handle_param.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024-2024 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_UNZIP_HANDLE_PARAM_H +#define SIGNATURETOOLS_UNZIP_HANDLE_PARAM_H + +#include +#include + +#include "code_sign_block.h" + +namespace OHOS { +namespace SignatureTools { +class UnzipHandleParam { +public: + UnzipHandleParam(CodeSignBlock& csb, std::pair& pairResult, bool isSign); + UnzipHandleParam(std::vector>& ret, std::string& ownerID, bool isSign); + CodeSignBlock& GetCodeSignBlock(); + std::pair& GetPairResult(); + std::vector>* GetRet(); + std::string& GetOwnerID(); + bool IsSign(); + +private: + CodeSignBlock csb; + std::pair pairResult; + std::vector> ret; + std::string ownerID; + bool isSign; +}; +} // namespace SignatureTools +} // namespace OHOS + +#endif \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/datastructure/src/code_sign_block.cpp b/hapsigntool_cpp/codesigning/datastructure/src/code_sign_block.cpp new file mode 100644 index 0000000000000000000000000000000000000000..91fccfa35f7f2a4933cb2bb1c52ed7b84de59004 --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/src/code_sign_block.cpp @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2024-2024 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 "code_sign_block.h" +#include "merkle_tree_extension.h" + +namespace OHOS { +namespace SignatureTools { + +CodeSignBlock::CodeSignBlock() +{ +} + +CodeSignBlock::~CodeSignBlock() +{ +} + +void CodeSignBlock::AddOneMerkleTree(const std::string& key, std::vector& merkleTree) +{ + if (key.empty()) { + return; + } + if (merkleTreeMap.find(key) == merkleTreeMap.end()) { + if (merkleTree.empty()) { + merkleTreeMap.insert(std::make_pair(key, std::vector(0))); + } else { + merkleTreeMap.insert(std::make_pair(key, merkleTree)); + } + } +} + +std::vector CodeSignBlock::GetOneMerkleTreeByFileName(const std::string& key) +{ + if (key.empty()) { + return std::vector(); + } + return merkleTreeMap[key]; +} + +void CodeSignBlock::SetCodeSignBlockFlag() +{ + int flags = CodeSignBlockHeader::FLAG_MERKLE_TREE_INLINED; + if (nativeLibInfoSegment.GetSectionNum() != 0) { + flags |= CodeSignBlockHeader::FLAG_NATIVE_LIB_INCLUDED; + } + codeSignBlockHeader.SetFlags(flags); +} + +void CodeSignBlock::SetSegmentNum() +{ + codeSignBlockHeader.SetSegmentNum(static_cast(segmentHeaderList.size())); +} + +void CodeSignBlock::AddToSegmentList(SegmentHeader sh) +{ + segmentHeaderList.push_back(sh); +} + +std::vector& CodeSignBlock::GetSegmentHeaderList() +{ + return segmentHeaderList; +} + +void CodeSignBlock::SetSegmentHeaders() +{ + // fs-verity info segment + SegmentHeader tempVar(SegmentHeader::CSB_FSVERITY_INFO_SEG, FsVerityInfoSegment::FS_VERITY_INFO_SEGMENT_SIZE); + segmentHeaderList.push_back(tempVar); + // hap info segment + SegmentHeader tempVar2(SegmentHeader::CSB_HAP_META_SEG, hapInfoSegment.GetSize()); + segmentHeaderList.push_back(tempVar2); + // native lib info segment + SegmentHeader tempVar3(SegmentHeader::CSB_NATIVE_LIB_INFO_SEG, nativeLibInfoSegment.Size()); + segmentHeaderList.push_back(tempVar3); +} + +CodeSignBlockHeader& CodeSignBlock::GetCodeSignBlockHeader() +{ + return codeSignBlockHeader; +} + +void CodeSignBlock::SetCodeSignBlockHeader(CodeSignBlockHeader& csbHeader) +{ + codeSignBlockHeader = csbHeader; +} + +void CodeSignBlock::SetFsVerityInfoSegment(FsVerityInfoSegment& fsVeritySeg) +{ + fsVerityInfoSegment = fsVeritySeg; +} + +HapInfoSegment& CodeSignBlock::GetHapInfoSegment() +{ + return hapInfoSegment; +} + +void CodeSignBlock::SetHapInfoSegment(HapInfoSegment& hapSeg) +{ + hapInfoSegment = hapSeg; +} + +NativeLibInfoSegment& CodeSignBlock::GetSoInfoSegment() +{ + return nativeLibInfoSegment; +} + +void CodeSignBlock::SetSoInfoSegment(NativeLibInfoSegment soSeg) +{ + nativeLibInfoSegment = soSeg; +} + +void CodeSignBlock::ToByteArray(std::vector& ret) +{ + std::unique_ptr bf = std::make_unique + (ByteBuffer(codeSignBlockHeader.GetBlockSize())); + std::vector codeSignBlockHeaderVec; + codeSignBlockHeader.ToByteArray(codeSignBlockHeaderVec); + bf->PutData(codeSignBlockHeaderVec.data(), codeSignBlockHeaderVec.size()); + for (auto &sh : segmentHeaderList) { + std::vector shVec; + sh.ToByteArray(shVec); + bf->PutData(shVec.data(), shVec.size()); + } + bf->PutData(zeroPadding.data(), zeroPadding.size()); + // Hap merkle tree + bf->PutData(merkleTreeMap["Hap"].data(), merkleTreeMap["Hap"].size()); + std::vector fsVerityInfoSegmentVec; + fsVerityInfoSegment.ToByteArray(fsVerityInfoSegmentVec); + bf->PutData(fsVerityInfoSegmentVec.data(), fsVerityInfoSegmentVec.size()); + std::vector hapInfoSegmentVec; + hapInfoSegment.ToByteArray(hapInfoSegmentVec); + bf->PutData(hapInfoSegmentVec.data(), hapInfoSegmentVec.size()); + std::vector nativeLibInfoSegmentVec; + nativeLibInfoSegment.ToByteArray(nativeLibInfoSegmentVec); + bf->PutData(nativeLibInfoSegmentVec.data(), nativeLibInfoSegmentVec.size()); + + ret = std::vector(bf->GetBufferPtr(), bf->GetBufferPtr() + bf->GetPosition()); +} + +void CodeSignBlock::ComputeSegmentOffset() +{ + // 1) the first segment is placed after merkle tree + int segmentOffset = CodeSignBlockHeader::Size() + + segmentHeaderList.size() * SegmentHeader::SEGMENT_HEADER_LENGTH + + zeroPadding.size() + GetOneMerkleTreeByFileName("Hap").size(); + for (int i = 0; i < segmentHeaderList.size(); i++) { + segmentHeaderList[i].SetSegmentOffset(static_cast(segmentOffset)); + segmentOffset += segmentHeaderList[i].GetSegmentSize(); + } +} + +int64_t CodeSignBlock::ComputeMerkleTreeOffset(int64_t codeSignBlockOffset) +{ + int64_t sizeWithoutMerkleTree = CodeSignBlockHeader::Size() + + SEGMENT_HEADER_COUNT * SegmentHeader::SEGMENT_HEADER_LENGTH; + // add code sign block offset while computing align position for merkle tree + int64_t residual = (codeSignBlockOffset + sizeWithoutMerkleTree) % PAGE_SIZE_4K; + if (residual == 0) { + zeroPadding = std::vector(0); + } else { + zeroPadding = std::vector(static_cast(PAGE_SIZE_4K - residual)); + } + return codeSignBlockOffset + sizeWithoutMerkleTree + zeroPadding.size(); +} + +void CodeSignBlock::GenerateCodeSignBlockByte(int64_t fsvTreeOffset, std::vector& ret) +{ + // 1) compute overall block size without merkle tree + int64_t csbSize = CodeSignBlockHeader::Size() + + static_cast(segmentHeaderList.size()) * SegmentHeader::SEGMENT_HEADER_LENGTH + + zeroPadding.size() + + GetOneMerkleTreeByFileName("Hap").size() + + fsVerityInfoSegment.Size() + + hapInfoSegment.GetSize() + + nativeLibInfoSegment.Size(); + Extension* ext = hapInfoSegment.GetSignInfo().GetExtensionByType(MerkleTreeExtension::MERKLE_TREE_INLINED); + if (ext != nullptr) { + MerkleTreeExtension* merkleTreeExtension = (MerkleTreeExtension*)(ext); + merkleTreeExtension->SetMerkleTreeOffset(fsvTreeOffset); + } + codeSignBlockHeader.SetBlockSize(csbSize); + // 2) generate byte array of complete code sign block + ToByteArray(ret); +} + +} +} \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/datastructure/src/code_sign_block_header.cpp b/hapsigntool_cpp/codesigning/datastructure/src/code_sign_block_header.cpp new file mode 100644 index 0000000000000000000000000000000000000000..42a87c42cdd032925cc8b2d0ef22c92e12b4b214 --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/src/code_sign_block_header.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2024-2024 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 "code_sign_block_header.h" + +namespace OHOS { +namespace SignatureTools { + +CodeSignBlockHeader::CodeSignBlockHeader() +{ + magic = MAGIC_NUM; + version = CODE_SIGNING_VERSION; + reserved = std::vector(RESERVED_BYTE_ARRAY_LENGTH); +} + +CodeSignBlockHeader::CodeSignBlockHeader(Builder* builder) +{ + this->magic = builder->magic; + this->version = builder->version; + this->blockSize = builder->blockSize; + this->segmentNum = builder->segmentNum; + this->flags = builder->flags; + this->reserved = builder->reserved; +} + +CodeSignBlockHeader::~CodeSignBlockHeader() +{ +} + +void CodeSignBlockHeader::SetSegmentNum(int num) +{ + segmentNum = num; +} + +int CodeSignBlockHeader::GetSegmentNum() +{ + return segmentNum; +} + +void CodeSignBlockHeader::SetBlockSize(int64_t size) +{ + blockSize = static_cast(size); +} + +int CodeSignBlockHeader::GetBlockSize() +{ + return blockSize; +} + +void CodeSignBlockHeader::SetFlags(int flags) +{ + this->flags = flags; +} + +void CodeSignBlockHeader::ToByteArray(std::vector& ret) +{ + ByteBuffer bf(Size()); + bf.PutInt64(magic); + bf.PutInt32(version); + bf.PutInt32(blockSize); + bf.PutInt32(segmentNum); + bf.PutInt32(flags); + bf.PutData((const char*)reserved.data(), reserved.size()); + ret = std::vector(bf.GetBufferPtr(), bf.GetBufferPtr() + bf.GetPosition()); +} + +CodeSignBlockHeader* CodeSignBlockHeader::FromByteArray(std::vector& bytes) +{ + if (bytes.size() != Size()) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed package in CodeSignBlockHeader is different in size from the \ + standard header size."); + return nullptr; + } + ByteBuffer bf(bytes.size()); + bf.PutData((const char*)bytes.data(), bytes.size()); + bf.Flip(); + int64_t inMagic; + bf.GetInt64(inMagic); + if (inMagic != MAGIC_NUM) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed package has the wrong magic number in the CodeSignBlockHeader."); + return nullptr; + } + int inVersion; + bf.GetInt32(inVersion); + if (inVersion != CODE_SIGNING_VERSION) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed package has the wrong code signing version in the CodeSignBlockHeader."); + return nullptr; + } + int inBlockSize; + bf.GetInt32(inBlockSize); + int inSegmentNum; + bf.GetInt32(inSegmentNum); + if (inSegmentNum != SEGMENT_NUM) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed package has the wrong segment number in the CodeSignBlockHeader."); + return nullptr; + } + int inFlags; + bf.GetInt32(inFlags); + if (inFlags < 0 || inFlags >(FLAG_MERKLE_TREE_INLINED + FLAG_NATIVE_LIB_INCLUDED)) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed package has the wrong flag in the CodeSignBlockHeader."); + return nullptr; + } + std::vector inReserved(RESERVED_BYTE_ARRAY_LENGTH); + bf.GetByte(inReserved.data(), RESERVED_BYTE_ARRAY_LENGTH); + CodeSignBlockHeader::Builder* tempVar = new CodeSignBlockHeader::Builder(); + CodeSignBlockHeader* codeSignBlockHeader = tempVar->SetMagic(inMagic)->SetVersion(inVersion)-> + SetBlockSize(inBlockSize)->SetSegmentNum(inSegmentNum)-> + SetFlags(inFlags)->SetReserved(inReserved)->Build(); + delete tempVar; + return codeSignBlockHeader; +} + +int CodeSignBlockHeader::Size() +{ + return MAGIC_BYTE_ARRAY_LENGTH + MAGIC_BYTE_LENGTH * MAGIC_BYTE_LENGTH + RESERVED_BYTE_ARRAY_LENGTH; +} + +CodeSignBlockHeader::Builder* CodeSignBlockHeader::Builder::SetMagic(int64_t magic) +{ + this->magic = magic; + return this; +} + +CodeSignBlockHeader::Builder* CodeSignBlockHeader::Builder::SetVersion(int version) +{ + this->version = version; + return this; +} + +CodeSignBlockHeader::Builder* CodeSignBlockHeader::Builder::SetBlockSize(int blockSize) +{ + this->blockSize = blockSize; + return this; +} + +CodeSignBlockHeader::Builder* CodeSignBlockHeader::Builder::SetSegmentNum(int segmentNum) +{ + this->segmentNum = segmentNum; + return this; +} + +CodeSignBlockHeader::Builder* CodeSignBlockHeader::Builder::SetFlags(int flags) +{ + this->flags = flags; + return this; +} + +CodeSignBlockHeader::Builder* CodeSignBlockHeader::Builder::SetReserved(std::vector& reserved) +{ + this->reserved = reserved; + return this; +} + +CodeSignBlockHeader* CodeSignBlockHeader::Builder::Build() +{ + return new CodeSignBlockHeader(this); +} + +CodeSignBlockHeader::Builder::~Builder() +{ +} + +} +} \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/datastructure/src/elf_sign_block.cpp b/hapsigntool_cpp/codesigning/datastructure/src/elf_sign_block.cpp new file mode 100644 index 0000000000000000000000000000000000000000..575ca658abacd2fd6bd491ced241f8ed5477463c --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/src/elf_sign_block.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2024-2024 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 "elf_sign_block.h" + +namespace OHOS { +namespace SignatureTools { + +ElfSignBlock::ElfSignBlock() +{ + type = MERKLE_TREE_INLINED; +} + +ElfSignBlock::ElfSignBlock(int32_t paddingSize, std::vector &merkleTreeData, + FsVerityDescriptorWithSign &descriptorWithSign) +{ + std::vector inMerkleTreeData; + if (!merkleTreeData.empty()) { + inMerkleTreeData = merkleTreeData; + } + treeLength = paddingSize + inMerkleTreeData.size(); + merkleTreeWithPadding.resize(treeLength); + std::copy(inMerkleTreeData.begin(), inMerkleTreeData.end(), merkleTreeWithPadding.begin() + paddingSize); + this->descriptorWithSign = descriptorWithSign; +} + +int32_t ElfSignBlock::Size() +{ + int tmpVariable = 2; + return FsVerityDescriptorWithSign::INTEGER_BYTES * tmpVariable + + merkleTreeWithPadding.size() + descriptorWithSign.Size(); +} + +std::vector& ElfSignBlock::GetMerkleTreeWithPadding() +{ + return merkleTreeWithPadding; +} + +int64_t ElfSignBlock::GetDataSize() +{ + return descriptorWithSign.GetFsVerityDescriptor().GetFileSize(); +} + +int64_t ElfSignBlock::GetTreeOffset() +{ + return descriptorWithSign.GetFsVerityDescriptor().GetMerkleTreeOffset(); +} + +std::vector ElfSignBlock::GetSignature() +{ + return descriptorWithSign.GetSignature(); +} + +void ElfSignBlock::ToByteArray(std::vector& ret) +{ + std::unique_ptr bf = std::make_unique(Size()); + bf->PutInt32(type); + bf->PutInt32(merkleTreeWithPadding.size()); + bf->PutData(merkleTreeWithPadding.data(), merkleTreeWithPadding.size()); + std::vector descriptorWithSignArr; + descriptorWithSign.ToByteArray(descriptorWithSignArr); + bf->PutData(descriptorWithSignArr.data(), descriptorWithSignArr.size()); + ret = std::vector(bf->GetBufferPtr(), bf->GetBufferPtr() + bf->GetLimit()); +} + +bool ElfSignBlock::FromByteArray(std::vector& bytes, ElfSignBlock& elfSignBlock) +{ + std::unique_ptr bf = std::make_unique(bytes.size()); + bf->PutData(bytes.data(), bytes.size()); + bf->Flip(); + int32_t inTreeType = 0; + bf->GetInt32(inTreeType); + if (MERKLE_TREE_INLINED != inTreeType) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed data has the wrong merkle tree type in the ElfSignBlock"); + return false; + } + int32_t inTreeLength = 0; + bf->GetInt32(inTreeLength); + std::vector treeWithPadding(inTreeLength); + bf->GetByte(treeWithPadding.data(), treeWithPadding.size()); + int32_t inFsdType = 0; + bf->GetInt32(inFsdType); + if (FsVerityDescriptor::FS_VERITY_DESCRIPTOR_TYPE != inFsdType) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed data has the wrong fs-verify descriptor type in the ElfSignBlock"); + return false; + } + int32_t inFsdLength = 0; + int tmpVariable = 2; + bf->GetInt32(inFsdLength); + if (bytes.size() != FsVerityDescriptorWithSign::INTEGER_BYTES * tmpVariable + inTreeLength + + FsVerityDescriptorWithSign::INTEGER_BYTES * tmpVariable + inFsdLength) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed data has the wrong signature length in the ElfSignBlock"); + return false; + } + std::vector fsdArray(FsVerityDescriptor::DESCRIPTOR_SIZE); + bf->GetByte(fsdArray.data(), fsdArray.size()); + FsVerityDescriptor fsd = FsVerityDescriptor::FromByteArray(fsdArray); + if (inFsdLength != fsd.GetSignSize() + FsVerityDescriptor::DESCRIPTOR_SIZE) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed data has the wrong signed size in the ElfSignBlock"); + return false; + } + std::vector inSignature(inFsdLength - FsVerityDescriptor::DESCRIPTOR_SIZE); + bf->GetByte(inSignature.data(), inSignature.size()); + FsVerityDescriptorWithSign fsVerityDescriptorWithSign(inFsdType, inFsdLength, fsd, inSignature); + elfSignBlock.type = inTreeType; + elfSignBlock.treeLength = inTreeLength; + elfSignBlock.merkleTreeWithPadding = treeWithPadding; + elfSignBlock.descriptorWithSign = fsVerityDescriptorWithSign; + return true; +} + +int32_t ElfSignBlock::ComputeMerkleTreePaddingLength(int64_t signBlockOffset) +{ + int tmpVariable = 2; + return (int32_t)(PAGE_SIZE_4K - (signBlockOffset + FsVerityDescriptorWithSign::INTEGER_BYTES * tmpVariable) + % PAGE_SIZE_4K) % PAGE_SIZE_4K; +} + +} +} \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/datastructure/src/extension.cpp b/hapsigntool_cpp/codesigning/datastructure/src/extension.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e16f547906de7810e81bb7d974ac3a73426acb60 --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/src/extension.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024-2024 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 "extension.h" +#include "byte_buffer.h" + +namespace OHOS { +namespace SignatureTools { + +const int32_t Extension::EXTENSION_HEADER_SIZE = 8; + +Extension::Extension() +{ + type = 0; + size = 0; +} + +Extension::Extension(int32_t type, int32_t size) +{ + this->type = type; + this->size = size; +} + +Extension::~Extension() +{ +} + +int32_t Extension::GetSize() +{ + return Extension::EXTENSION_HEADER_SIZE; +} + +bool Extension::IsType(int32_t type) +{ + return this->type == type; +} + +void Extension::ToByteArray(std::vector& ret) +{ + std::unique_ptr bf = std::make_unique + (ByteBuffer(Extension::EXTENSION_HEADER_SIZE)); + bf->PutInt32(type); + bf->PutInt32(size); + bf->Flip(); + char dataArr[Extension::EXTENSION_HEADER_SIZE] = { 0 }; + bf->GetData(dataArr, Extension::EXTENSION_HEADER_SIZE); + ret = std::vector(dataArr, dataArr + Extension::EXTENSION_HEADER_SIZE); +} + +} +} \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/datastructure/src/fs_verity_info_segment.cpp b/hapsigntool_cpp/codesigning/datastructure/src/fs_verity_info_segment.cpp new file mode 100644 index 0000000000000000000000000000000000000000..50971cb26253f17560747072d6a9a6f2025b6435 --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/src/fs_verity_info_segment.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2024-2024 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 "fs_verity_info_segment.h" + +namespace OHOS { +namespace SignatureTools { + +FsVerityInfoSegment::FsVerityInfoSegment() +{ + magic = MAGIC; + reserved = std::vector(RESERVED_BYTE_ARRAY_LENGTH); +} + +FsVerityInfoSegment::FsVerityInfoSegment(int8_t version, int8_t hashAlgorithm, int8_t log2BlockSize) +{ + magic = MAGIC; + this->version = version; + this->hashAlgorithm = hashAlgorithm; + this->log2BlockSize = log2BlockSize; + reserved = std::vector(RESERVED_BYTE_ARRAY_LENGTH); +} + +FsVerityInfoSegment::FsVerityInfoSegment(int magic, int8_t version, int8_t hashAlgorithm, + int8_t log2BlockSize, std::vector reserved) +{ + this->magic = magic; + this->version = version; + this->hashAlgorithm = hashAlgorithm; + this->log2BlockSize = log2BlockSize; + this->reserved = reserved; +} + +FsVerityInfoSegment:: ~FsVerityInfoSegment() +{ +} + +int FsVerityInfoSegment::Size() +{ + return FS_VERITY_INFO_SEGMENT_SIZE; +} + +void FsVerityInfoSegment::ToByteArray(std::vector& ret) +{ + std::unique_ptr bf = std::make_unique(FS_VERITY_INFO_SEGMENT_SIZE); + bf->PutInt32(magic); + bf->PutByte(version); + bf->PutByte(hashAlgorithm); + bf->PutByte(log2BlockSize); + bf->PutData(reserved.data(), reserved.size()); + ret = std::vector(bf->GetBufferPtr(), bf->GetBufferPtr() + bf->GetPosition()); +} + +FsVerityInfoSegment FsVerityInfoSegment::FromByteArray(std::vector &bytes) +{ + if (bytes.size() != FS_VERITY_INFO_SEGMENT_SIZE) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed data has the wrong signed size in the FsVerityInfoSegment"); + return FsVerityInfoSegment(); + } + + ByteBuffer bf(bytes.size()); + bf.PutData((const char*)bytes.data(), bytes.size()); + bf.SetPosition(0); + int inMagic; + bf.GetInt32(inMagic); + if (inMagic != MAGIC) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed data has the wrong magic number in the FsVerityInfoSegment"); + return FsVerityInfoSegment(); + } + + int8_t inVersion; + bf.GetInt8(inVersion); + if (inVersion != FsVerityDescriptor::VERSION) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed data has the wrong version in the FsVerityInfoSegment"); + return FsVerityInfoSegment(); + } + + int8_t inHashAlgorithm; + bf.GetInt8(inHashAlgorithm); + if (inHashAlgorithm != FsVerityGenerator::GetFsVerityHashAlgorithm()) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed data has the wrong hashAlgorithm in the FsVerityInfoSegment"); + return FsVerityInfoSegment(); + } + + int8_t inLog2BlockSize; + bf.GetInt8(inLog2BlockSize); + if (inLog2BlockSize != FsVerityGenerator::GetLog2BlockSize()) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed data has the wrong log2BlockSize in the FsVerityInfoSegment"); + return FsVerityInfoSegment(); + } + + std::vector inReservedBytes(RESERVED_BYTE_ARRAY_LENGTH); + char reverseArr[RESERVED_BYTE_ARRAY_LENGTH]; + bf.GetData(reverseArr, RESERVED_BYTE_ARRAY_LENGTH); + std::vector reverseData(reverseArr, reverseArr + RESERVED_BYTE_ARRAY_LENGTH); + + return FsVerityInfoSegment(inMagic, inVersion, inHashAlgorithm, inLog2BlockSize, reverseData); +} + +} +} \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/datastructure/src/hap_info_segment.cpp b/hapsigntool_cpp/codesigning/datastructure/src/hap_info_segment.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7f18961ee477a3cb033c902f14fe13fe25211817 --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/src/hap_info_segment.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2024-2024 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 "hap_info_segment.h" + +namespace OHOS { +namespace SignatureTools { + +HapInfoSegment::HapInfoSegment() +{ + std::vector emptyVector; + magic = HapInfoSegment::MAGIC_NUM; + signInfo = SignInfo(0, 0, 0, emptyVector, emptyVector); +} + +HapInfoSegment::HapInfoSegment(int32_t magic, SignInfo signInfo) +{ + this->magic = magic; + this->signInfo = signInfo; +} + +void HapInfoSegment::SetSignInfo(SignInfo signInfo) +{ + this->signInfo = signInfo; +} + +SignInfo& HapInfoSegment::GetSignInfo() +{ + return signInfo; +} + +int32_t HapInfoSegment::GetSize() +{ + return HapInfoSegment::MAGIC_NUM_BYTES + signInfo.GetSize(); +} + +void HapInfoSegment::ToByteArray(std::vector &ret) +{ + std::vector hapSignInfoByteArray; + signInfo.ToByteArray(hapSignInfoByteArray); + std::unique_ptr bf = std::make_unique + (ByteBuffer(HapInfoSegment::MAGIC_NUM_BYTES + hapSignInfoByteArray.size())); + bf->PutInt32(magic); + bf->PutData(hapSignInfoByteArray.data(), hapSignInfoByteArray.size()); + ret = std::vector(bf->GetBufferPtr(), bf->GetBufferPtr() + bf->GetPosition()); + return; +} + +HapInfoSegment HapInfoSegment::FromByteArray(std::vector bytes) +{ + std::unique_ptr bf = std::make_unique(ByteBuffer(bytes.size())); + bf->PutData(bytes.data(), bytes.size()); + bf->Flip(); + int32_t inMagic = 0; + bf->GetInt32(inMagic); + if (inMagic != HapInfoSegment::MAGIC_NUM) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed data has the wrong magic number in the HapInfoSegment."); + return HapInfoSegment(); + } + if (bytes.size() <= HapInfoSegment::MAGIC_NUM_BYTES) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed data has the wrong bytes size in the HapInfoSegment."); + return HapInfoSegment(); + } + std::vector hapSignInfoByteArray(bytes.size() - HapInfoSegment::MAGIC_NUM_BYTES); + bf->GetByte(hapSignInfoByteArray.data(), hapSignInfoByteArray.size()); + SignInfo inHapSignInfo = SignInfo::FromByteArray(hapSignInfoByteArray); + if (inHapSignInfo.GetDataSize() % HapInfoSegment::CHUNK_SIZE != 0) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "Invalid dataSize, the dataSize is not an integer multiple of 4096."); + return HapInfoSegment(); + } + if (inHapSignInfo.GetExtensionNum() != SignInfo::MAX_EXTENSION_NUM) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed data has the wrong extensionNum in the HapInfoSegment."); + return HapInfoSegment(); + } + return HapInfoSegment(inMagic, inHapSignInfo); +} + +} +} \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/datastructure/src/merkle_tree_extension.cpp b/hapsigntool_cpp/codesigning/datastructure/src/merkle_tree_extension.cpp new file mode 100644 index 0000000000000000000000000000000000000000..95ba27b65839d46f4db0027f760009a7eb13826e --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/src/merkle_tree_extension.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2024-2024 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 "merkle_tree_extension.h" + +namespace OHOS { +namespace SignatureTools { + +MerkleTreeExtension::MerkleTreeExtension() + : Extension(MERKLE_TREE_INLINED, MERKLE_TREE_EXTENSION_DATA_SIZE) +{ + merkleTreeSize = 0; + merkleTreeOffset = 0; +} + +MerkleTreeExtension::MerkleTreeExtension(int64_t merkleTreeSize, int64_t merkleTreeOffset, std::vector rootHash) + : Extension(MERKLE_TREE_INLINED, MERKLE_TREE_EXTENSION_DATA_SIZE) +{ + this->merkleTreeSize = merkleTreeSize; + this->merkleTreeOffset = merkleTreeOffset; + this->rootHash = rootHash; +} + +MerkleTreeExtension::~MerkleTreeExtension() +{ +} + +int32_t MerkleTreeExtension::GetSize() +{ + return Extension::EXTENSION_HEADER_SIZE + MERKLE_TREE_EXTENSION_DATA_SIZE; +} + +int64_t MerkleTreeExtension::GetMerkleTreeSize() +{ + return merkleTreeSize; +} + +int64_t MerkleTreeExtension::GetMerkleTreeOffset() +{ + return merkleTreeOffset; +} + +void MerkleTreeExtension::SetMerkleTreeOffset(int64_t offset) +{ + merkleTreeOffset = offset; +} + +void MerkleTreeExtension::ToByteArray(std::vector& ret) +{ + std::unique_ptr bf = std::make_unique(ByteBuffer( + Extension::EXTENSION_HEADER_SIZE + MERKLE_TREE_EXTENSION_DATA_SIZE)); + std::vector extByteArr; + Extension::ToByteArray(extByteArr); + bf->PutData(extByteArr.data(), extByteArr.size()); + bf->PutInt64(merkleTreeSize); + bf->PutInt64(merkleTreeOffset); + bf->PutData(rootHash.data(), rootHash.size()); + ret = std::vector(bf->GetBufferPtr(), bf->GetBufferPtr() + bf->GetCapacity()); +} + +MerkleTreeExtension* MerkleTreeExtension::FromByteArray(std::vector& bytes) +{ + std::unique_ptr bf = std::make_unique(ByteBuffer(bytes.size())); + bf->PutData(bytes.data(), bytes.size()); + bf->Flip(); + int64_t inMerkleTreeSize = 0; + bf->GetInt64(inMerkleTreeSize); + if (inMerkleTreeSize % PAGE_SIZE_4K != 0) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed package's merkletree size is not an integer multiple of 4096"); + return nullptr; + } + int64_t inMerkleTreeOffset = 0; + bf->GetInt64(inMerkleTreeOffset); + if (inMerkleTreeOffset % PAGE_SIZE_4K != 0) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed package's merkletree offset is not an integer multiple of 4096"); + return nullptr; + } + std::vector inRootHash(ROOT_HASH_SIZE); + bf->GetByte(inRootHash.data(), inRootHash.size()); + return new MerkleTreeExtension(inMerkleTreeSize, inMerkleTreeOffset, inRootHash); +} + +} +} \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/datastructure/src/native_lib_info_segment.cpp b/hapsigntool_cpp/codesigning/datastructure/src/native_lib_info_segment.cpp new file mode 100644 index 0000000000000000000000000000000000000000..50054c1961d93d514d7f99de021c335418ba3e7c --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/src/native_lib_info_segment.cpp @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2024-2024 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 "native_lib_info_segment.h" + +namespace OHOS { +namespace SignatureTools { + +NativeLibInfoSegment::NativeLibInfoSegment() +{ + magic = MAGIC_NUM; + zeroPadding = std::vector(0); + fileNameListBlockSize = 0; + segmentSize = 0; + sectionNum = 0; + signInfoListBlockSize = 0; +} + +NativeLibInfoSegment::NativeLibInfoSegment(int32_t magic, + int32_t segmentSize, + int32_t sectionNum, + std::vector signedFilePosList, + std::vector fileNameList, + std::vector signInfoList, + std::vector zeroPadding +) +{ + this->magic = magic; + this->segmentSize = segmentSize; + this->sectionNum = sectionNum; + this->signedFilePosList = signedFilePosList; + this->fileNameList = fileNameList; + this->signInfoList = signInfoList; + this->zeroPadding = zeroPadding; + fileNameListBlockSize = 0; + signInfoListBlockSize = 0; +} + +void NativeLibInfoSegment::SetSoInfoList(std::vector> &soInfoList) +{ + this->soInfoList = soInfoList; + // Once map is set, update length, sectionNum as well + sectionNum = soInfoList.size(); + // generate file name list and sign info list + GenerateList(); +} + +int32_t NativeLibInfoSegment::GetSectionNum() +{ + return sectionNum; +} + +std::vector NativeLibInfoSegment::GetFileNameList() +{ + return fileNameList; +} + +std::vector NativeLibInfoSegment::GetSignInfoList() +{ + return signInfoList; +} + +int32_t NativeLibInfoSegment::Size() +{ + int blockSize = MAGIC_LENGTH_SECNUM_BYTES; + blockSize += signedFilePosList.size() * SIGNED_FILE_POS_SIZE; + blockSize += fileNameListBlockSize + zeroPadding.size() + signInfoListBlockSize; + return blockSize; +} + +void NativeLibInfoSegment::ToByteArray(std::vector &ret) +{ + std::unique_ptr bf = std::make_unique(ByteBuffer(Size())); + std::vector empt(Size()); + bf->PutData(empt.data(), empt.size()); + bf->Clear(); + bf->PutInt32(magic); + bf->PutInt32(segmentSize); + bf->PutInt32(sectionNum); + for (SignedFilePos &offsetAndSize : signedFilePosList) { + bf->PutInt32(offsetAndSize.GetFileNameOffset()); + bf->PutInt32(offsetAndSize.GetFileNameSize()); + bf->PutInt32(offsetAndSize.GetSignInfoOffset()); + bf->PutInt32(offsetAndSize.GetSignInfoSize()); + } + for (std::string &fileName : fileNameList) { + bf->PutData(fileName.c_str(), fileName.size() * sizeof(char)); + } + bf->PutData(zeroPadding.data(), zeroPadding.size()); + for (SignInfo &signInfo : signInfoList) { + std::vector signInfoArr; + signInfo.ToByteArray(signInfoArr); + bf->PutData(signInfoArr.data(), signInfoArr.size()); + } + ret = std::vector(bf->GetBufferPtr(), bf->GetBufferPtr() + bf->GetPosition()); + return; +} + +NativeLibInfoSegment NativeLibInfoSegment::FromByteArray(std::vector &bytes) +{ + std::unique_ptr bf = std::make_unique(ByteBuffer(bytes.size())); + bf->PutData(bytes.data(), bytes.size()); + bf->Flip(); + int32_t inMagic = 0; + int32_t inSegmentSize = 0; + int32_t inSectionNum = 0; + bool checkFlag = CheckBuffer(bf.get(), inMagic, inSegmentSize, inSectionNum); + if (!checkFlag) { + return NativeLibInfoSegment(); + } + std::vector inSignedFilePosList; + for (int i = 0; i < inSectionNum; i++) { + std::vector entry(SIGNED_FILE_POS_SIZE, 0); + bf->GetByte(entry.data(), entry.size()); + inSignedFilePosList.push_back(SignedFilePos::FromByteArray(entry)); + } + // parse file name list + std::vector inFileNameList; + int fileNameListSize = 0; + for (SignedFilePos &pos : inSignedFilePosList) { + std::vector fileNameBuffer(pos.GetFileNameSize(), 0); + fileNameListSize += pos.GetFileNameSize(); + bf->SetPosition(pos.GetFileNameOffset()); + bf->GetData(fileNameBuffer.data(), fileNameBuffer.size()); + inFileNameList.push_back(std::string(fileNameBuffer.data(), fileNameBuffer.size())); + } + // parse zeroPadding + std::vector inZeroPadding((ALIGNMENT_FOR_SIGNINFO - fileNameListSize + % ALIGNMENT_FOR_SIGNINFO) % ALIGNMENT_FOR_SIGNINFO); + bf->GetByte(inZeroPadding.data(), inZeroPadding.size()); + // parse sign info list + std::vector inSignInfoList; + for (SignedFilePos &pos : inSignedFilePosList) { + if (pos.GetSignInfoOffset() % ALIGNMENT_FOR_SIGNINFO != 0) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The native lib's sign info offset is not an integer multiple of 4"); + return NativeLibInfoSegment(); + } + std::vector signInfoBuffer(pos.GetSignInfoSize()); + bf->SetPosition(pos.GetSignInfoOffset()); + bf->GetByte(signInfoBuffer.data(), signInfoBuffer.size()); + inSignInfoList.push_back(OHOS::SignatureTools::SignInfo::FromByteArray(signInfoBuffer)); + } + return NativeLibInfoSegment(inMagic, inSegmentSize, inSectionNum, inSignedFilePosList, + inFileNameList, inSignInfoList, inZeroPadding); +} + +bool NativeLibInfoSegment::CheckBuffer(ByteBuffer* bf, int32_t& inMagic, int32_t& inSegmentSize, + int32_t& inSectionNum) +{ + bf->GetInt32(inMagic); + if (inMagic != MAGIC_NUM) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed data has the wrong magic number in the NativeLibInfoSegment"); + return false; + } + bf->GetInt32(inSegmentSize); + if (inSegmentSize < 0) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed data has the wrong segmentSize in the NativeLibInfoSegment"); + return false; + } + bf->GetInt32(inSectionNum); + if (inSectionNum < 0) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed data has the wrong sectionNum in the NativeLibInfoSegment"); + return false; + } + return true; +} + +void NativeLibInfoSegment::GenerateList() +{ + // empty all before generate list + fileNameList.clear(); + signInfoList.clear(); + signedFilePosList.clear(); + int fileNameOffset = 0; + int signInfoOffset = 0; + for (std::pair &soInfo :soInfoList) { + std::string fileName = soInfo.first; + SignInfo& signInfo = soInfo.second; + int fileNameSizeInBytes = fileName.size() * sizeof(char); + int signInfoSizeInBytes = signInfo.GetSize() * sizeof(char); + fileNameList.push_back(fileName); + signInfoList.push_back(signInfo); + std::unique_ptr posPtr = std::make_unique(fileNameOffset, + fileNameSizeInBytes, signInfoOffset, signInfoSizeInBytes); + signedFilePosList.push_back(*posPtr.get()); + // increase fileNameOffset and signInfoOffset + fileNameOffset += fileNameSizeInBytes; + signInfoOffset += signInfoSizeInBytes; + } + fileNameListBlockSize = fileNameOffset; + signInfoListBlockSize = signInfoOffset; + // alignment for signInfo + zeroPadding = std::vector((ALIGNMENT_FOR_SIGNINFO - fileNameListBlockSize + % ALIGNMENT_FOR_SIGNINFO) % ALIGNMENT_FOR_SIGNINFO); + // after fileNameList and signInfoList is generated, update segment size + segmentSize = Size(); + // adjust file name and sign info offset base on segment start + int fileNameOffsetBase = MAGIC_LENGTH_SECNUM_BYTES + signedFilePosList.size() * SIGNED_FILE_POS_SIZE; + int signInfoOffsetBase = fileNameOffsetBase + fileNameListBlockSize; + for (SignedFilePos &pos : signedFilePosList) { + pos.IncreaseFileNameOffset(fileNameOffsetBase); + pos.IncreaseSignInfoOffset(signInfoOffsetBase + zeroPadding.size()); + } +} + +} +} diff --git a/hapsigntool_cpp/codesigning/datastructure/src/segment_header.cpp b/hapsigntool_cpp/codesigning/datastructure/src/segment_header.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6684bf471011b5af64b5344a6dc456a0d39e0a7e --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/src/segment_header.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2024-2024 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 "segment_header.h" + +namespace OHOS { +namespace SignatureTools { + +SegmentHeader::SegmentHeader() +{ +} + +SegmentHeader::SegmentHeader(int32_t type, int32_t segmentSize) :type(type), segmentOffset(0), segmentSize(segmentSize) +{ +} + +SegmentHeader::SegmentHeader(int32_t type, int32_t segmentOffset, + int32_t segmentSize) +{ + this->type = type; + this->segmentOffset = segmentOffset; + this->segmentSize = segmentSize; +} + +int32_t SegmentHeader::GetType() +{ + return type; +} + +void SegmentHeader::SetSegmentOffset(int32_t offset) +{ + segmentOffset = offset; +} + +int32_t SegmentHeader::GetSegmentOffset() +{ + return segmentOffset; +} + +int32_t SegmentHeader::GetSegmentSize() +{ + return segmentSize; +} + +void SegmentHeader::ToByteArray(std::vector &ret) +{ + std::unique_ptr bf = std::make_unique(ByteBuffer(SEGMENT_HEADER_LENGTH)); + bf->PutInt32(type); + bf->PutInt32(segmentOffset); + bf->PutInt32(segmentSize); + bf->Flip(); + ret = std::vector(bf->GetBufferPtr(), bf->GetBufferPtr() + bf.get()->GetLimit()); + return; +} + +std::unique_ptr SegmentHeader::FromByteArray(std::vector bytes) +{ + if (bytes.size() != SEGMENT_HEADER_LENGTH) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "The signed package has the wrong flag in the SegmentHeader"); + return std::unique_ptr(); + } + std::unique_ptr bf = std::make_unique(ByteBuffer(SEGMENT_HEADER_LENGTH)); + bf->PutData(bytes.data(), bytes.size()); + bf->Flip(); + int32_t inType = 0; + bf->GetInt32(inType); + if ((inType != CSB_FSVERITY_INFO_SEG) && (inType != CSB_HAP_META_SEG) + && (inType != CSB_NATIVE_LIB_INFO_SEG)) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "The signed package has the wrong type in the SegmentHeader"); + return std::unique_ptr(); + } + int32_t inSegmentOffset = 0; + bf->GetInt32(inSegmentOffset); + // segment offset is always larger than the size of CodeSignBlockHeader + int32_t inSegmentSize = 0; + bf->GetInt32(inSegmentSize); + if (inSegmentSize < 0) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed package has the wrong segmentsize in the SegmentHeader"); + return std::unique_ptr(); + } + return std::make_unique(inType, inSegmentOffset, inSegmentSize); +} + +} +} \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/datastructure/src/sign_info.cpp b/hapsigntool_cpp/codesigning/datastructure/src/sign_info.cpp new file mode 100644 index 0000000000000000000000000000000000000000..78becf0a92e5e35901a8cdb5515504e46c124973 --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/src/sign_info.cpp @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2024-2024 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_info.h" + +namespace OHOS { +namespace SignatureTools { + +SignInfo::SignInfo() +{ + saltSize = 0; + sigSize = 0; + flags = 0; + dataSize = 0; + salt = std::vector(); + extensionNum = 0; + extensionOffset = 0; + signature = std::vector(); + zeroPadding = std::vector(); +} + +SignInfo::SignInfo(int32_t saltSize, + int32_t flags, + int64_t dataSize, + std::vector &salt, + std::vector &sig) +{ + this->saltSize = saltSize; + this->flags = flags; + this->dataSize = dataSize; + if (salt.empty()) { + this->salt = std::vector(SALT_BUFFER_LENGTH, 0); + } else { + this->salt = salt; + } + signature = sig; + sigSize = sig.empty() ? 0 : sig.size(); + // align for extension after signature + zeroPadding = std::vector((SignInfo::SIGNATURE_ALIGNMENT + - (sigSize % SignInfo::SIGNATURE_ALIGNMENT)) + % SignInfo::SIGNATURE_ALIGNMENT, 0); + extensionNum = 0; + extensionOffset = 0; +} + +SignInfo::SignInfo(int32_t saltSize, + int32_t sigSize, + int32_t flags, + int64_t dataSize, + std::vector& salt, + int32_t extensionNum, + int32_t extensionOffset, + std::vector& signature, + std::vector& zeroPadding, + std::vector extensionList) +{ + this->saltSize = saltSize; + this->sigSize = sigSize; + this->flags = flags; + this->dataSize = dataSize; + this->salt = salt; + this->extensionNum = extensionNum; + this->extensionOffset = extensionOffset; + this->signature = signature; + this->zeroPadding = zeroPadding; + this->extensionList = extensionList; +} + +SignInfo::SignInfo(const SignInfo& other) +{ + this->saltSize = other.saltSize; + this->sigSize = other.sigSize; + this->flags = other.flags; + this->dataSize = other.dataSize; + this->salt = other.salt; + this->extensionNum = other.extensionNum; + this->extensionOffset = other.extensionOffset; + this->signature = other.signature; + this->zeroPadding = other.zeroPadding; + for (MerkleTreeExtension* ext : other.extensionList) { + MerkleTreeExtension* extTmp = new MerkleTreeExtension(*(MerkleTreeExtension*)(ext)); + this->extensionList.push_back(extTmp); + } +} + +SignInfo& SignInfo::operator=(const SignInfo& other) +{ + if (this == &other) { + return *this; + } + this->saltSize = other.saltSize; + this->sigSize = other.sigSize; + this->flags = other.flags; + this->dataSize = other.dataSize; + this->salt = other.salt; + this->extensionNum = other.extensionNum; + this->extensionOffset = other.extensionOffset; + this->signature = other.signature; + this->zeroPadding = other.zeroPadding; + for (Extension* ext : other.extensionList) { + MerkleTreeExtension* extTmp = new MerkleTreeExtension(*(MerkleTreeExtension*)(ext)); + this->extensionList.push_back(extTmp); + } + return *this; +} + +SignInfo::~SignInfo() +{ + for (Extension* ext : extensionList) { + if (ext) { + delete ext; + ext = nullptr; + } + } +} + +int32_t SignInfo::GetSize() +{ + int blockSize = SignInfo::SIGN_INFO_SIZE_WITHOUT_SIGNATURE + signature.size() + zeroPadding.size(); + for (Extension* ext : extensionList) { + blockSize += ext->GetSize(); + } + return blockSize; +} + +void SignInfo::AddExtension(MerkleTreeExtension* extension) +{ + extensionOffset = GetSize(); + extensionList.push_back(extension); + extensionNum = extensionList.size(); +} + +Extension* SignInfo::GetExtensionByType(int32_t type) +{ + for (Extension* ext : extensionList) { + if (ext->IsType(type)) { + return ext; + } + } + return nullptr; +} + +int32_t SignInfo::GetExtensionNum() +{ + return extensionNum; +} + +std::vector SignInfo::GetSignature() +{ + return signature; +} + +int64_t SignInfo::GetDataSize() +{ + return dataSize; +} + +void SignInfo::ToByteArray(std::vector &ret) +{ + std::unique_ptr bf = std::make_unique(ByteBuffer(GetSize())); + std::vector empt(GetSize()); + bf->PutData(empt.data(), empt.size()); + bf->Clear(); + bf->PutInt32(saltSize); + bf->PutInt32(sigSize); + bf->PutInt32(flags); + bf->PutInt64(dataSize); + bf->PutData(salt.data(), salt.size()); + bf->PutInt32(extensionNum); + bf->PutInt32(extensionOffset); + bf->PutData(signature.data(), signature.size()); + bf->PutData(zeroPadding.data(), zeroPadding.size()); + // put extension + for (Extension* ext : extensionList) { + std::vector ret; + ext->ToByteArray(ret); + bf->PutData(ret.data(), ret.size()); + } + bf->Flip(); + ret = std::vector(bf->GetBufferPtr(), bf->GetBufferPtr() + bf.get()->GetCapacity()); + return; +} + +std::vector SignInfo::ParseMerkleTreeExtension(ByteBuffer* bf, int32_t inExtensionNum) +{ + std::vector inExtensionList; + if (inExtensionNum == 1) { + // parse merkle tree extension + int32_t extensionType = 0; + bf->GetInt32(extensionType); + if (extensionType != MerkleTreeExtension::MERKLE_TREE_INLINED) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed package has the wrong extensionType in the SignInfo"); + return inExtensionList; + } + int32_t extensionSize = 0; + bf->GetInt32(extensionSize); + if (extensionSize != MerkleTreeExtension::MERKLE_TREE_EXTENSION_DATA_SIZE) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed package has the wrong extensionSize in the SignInfo"); + return inExtensionList; + } + std::vector merkleTreeExtension(MerkleTreeExtension::MERKLE_TREE_EXTENSION_DATA_SIZE, 0); + bf->GetByte(merkleTreeExtension.data(), merkleTreeExtension.size()); + MerkleTreeExtension* pMerkleTreeExtension = MerkleTreeExtension::FromByteArray(merkleTreeExtension); + if (pMerkleTreeExtension) { + inExtensionList.push_back(pMerkleTreeExtension); + } + } + return inExtensionList; +} + +SignInfo SignInfo::FromByteArray(std::vector bytes) +{ + std::unique_ptr bf = std::make_unique(ByteBuffer(bytes.size())); + bf->PutData(bytes.data(), bytes.size()); + bf->Flip(); + int32_t inSaltSize = 0; + bf->GetInt32(inSaltSize); + int32_t inSigSize = 0; + bf->GetInt32(inSigSize); + if (inSaltSize < 0 || inSigSize < 0) { + SIGNATURE_TOOLS_LOGE("Invalid saltSize or sigSize of SignInfo, saltSize: %d, sigSize: %d", + inSaltSize, inSigSize); + return SignInfo(); + } + int32_t inFlags = 0; + bf->GetInt32(inFlags); + if (inFlags != 0 && inFlags != SignInfo::FLAG_MERKLE_TREE_INCLUDED) { + SIGNATURE_TOOLS_LOGE("Invalid flags of SignInfo: %d", inFlags); + return SignInfo(); + } + int64_t inDataSize = 0; + bf->GetInt64(inDataSize); + if (inDataSize < 0) { + SIGNATURE_TOOLS_LOGE("Invalid dataSize of SignInfo"); + return SignInfo(); + } + std::vector inSalt(SignInfo::SALT_BUFFER_LENGTH, 0); + bf->GetByte(inSalt.data(), SignInfo::SALT_BUFFER_LENGTH); + int32_t inExtensionNum = 0; + bf->GetInt32(inExtensionNum); + if (inExtensionNum < 0 || inExtensionNum > SignInfo::MAX_EXTENSION_NUM) { + SIGNATURE_TOOLS_LOGE("Invalid extensionNum of SignInfo: %d", inExtensionNum); + return SignInfo(); + } + int32_t inExtensionOffset = 0; + bf->GetInt32(inExtensionOffset); + if (inExtensionOffset < 0 || inExtensionOffset % SignInfo::SIGNATURE_ALIGNMENT != 0) { + SIGNATURE_TOOLS_LOGE("Invalid extensionOffset of SignInfo: %d", inExtensionOffset); + return SignInfo(); + } + std::vector inSignature(inSigSize, 0); + bf->GetByte(inSignature.data(), inSigSize); + std::vector inZeroPadding((SignInfo::SIGNATURE_ALIGNMENT - (inSigSize % SignInfo::SIGNATURE_ALIGNMENT)) + % SignInfo::SIGNATURE_ALIGNMENT, 0); + bf->GetByte(inZeroPadding.data(), inZeroPadding.size()); + std::vector inExtensionList = ParseMerkleTreeExtension(bf.get(), inExtensionNum); + return SignInfo(inSaltSize, inSigSize, inFlags, inDataSize, inSalt, inExtensionNum, inExtensionOffset, + inSignature, inZeroPadding, inExtensionList); +} + +} +} \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/datastructure/src/signed_file_pos.cpp b/hapsigntool_cpp/codesigning/datastructure/src/signed_file_pos.cpp new file mode 100644 index 0000000000000000000000000000000000000000..101cba360c4c766c5bd00bebcef23eef13dbea85 --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/src/signed_file_pos.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024-2024 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 "signed_file_pos.h" + +namespace OHOS { +namespace SignatureTools { + +SignedFilePos::SignedFilePos(int32_t fileNameOffset, + int32_t fileNameSize, + int32_t signInfoOffset, + int32_t signInfoSize) + :fileNameOffset(fileNameOffset), + fileNameSize(fileNameSize), + signInfoOffset(signInfoOffset), + signInfoSize(signInfoSize) +{ +} + +int32_t SignedFilePos::GetFileNameOffset() +{ + return fileNameOffset; +} + +int32_t SignedFilePos::GetFileNameSize() +{ + return fileNameSize; +} + +int32_t SignedFilePos::GetSignInfoOffset() +{ + return signInfoOffset; +} + +int32_t SignedFilePos::GetSignInfoSize() +{ + return signInfoSize; +} + +void SignedFilePos::IncreaseFileNameOffset(int32_t incOffset) +{ + fileNameOffset += incOffset; +} + +void SignedFilePos::IncreaseSignInfoOffset(int32_t incOffset) +{ + signInfoOffset += incOffset; +} + +SignedFilePos SignedFilePos::FromByteArray(std::vector &bytes) +{ + std::unique_ptr bf = std::make_unique(ByteBuffer(bytes.size())); + bf->PutData(0, bytes.data(), bytes.size()); + int32_t inFileNameOffset = 0; + bf->GetInt32(inFileNameOffset); + int32_t inFileNameSize = 0; + bf->GetInt32(inFileNameSize); + int32_t inSignInfoOffset = 0; + bf->GetInt32(inSignInfoOffset); + int32_t inSignInfoSize = 0; + bf->GetInt32(inSignInfoSize); + return SignedFilePos(inFileNameOffset, inFileNameSize, inSignInfoOffset, inSignInfoSize); +} + +} +} \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/datastructure/src/unzip_handle_param.cpp b/hapsigntool_cpp/codesigning/datastructure/src/unzip_handle_param.cpp new file mode 100644 index 0000000000000000000000000000000000000000..81ad271310b14fc6654df2a4a3546d53e7de24a4 --- /dev/null +++ b/hapsigntool_cpp/codesigning/datastructure/src/unzip_handle_param.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024-2024 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 "unzip_handle_param.h" + +namespace OHOS { +namespace SignatureTools { + +UnzipHandleParam::UnzipHandleParam(CodeSignBlock& csb, std::pair& pairResult, + bool isSign) +{ + this->csb = csb; + this->pairResult = pairResult; + this->isSign = isSign; +} + +UnzipHandleParam::UnzipHandleParam(std::vector>& ret, + std::string& ownerID, bool isSign) +{ + this->ret = ret; + this->ownerID = ownerID; + this->isSign = isSign; +} + +CodeSignBlock& UnzipHandleParam::GetCodeSignBlock() +{ + return csb; +} + +std::pair& UnzipHandleParam::GetPairResult() +{ + return pairResult; +} + +std::vector>* UnzipHandleParam::GetRet() +{ + return &ret; +} + +std::string& UnzipHandleParam::GetOwnerID() +{ + return ownerID; +} + +bool UnzipHandleParam::IsSign() +{ + return isSign; +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/fsverity/.gitignore b/hapsigntool_cpp/codesigning/fsverity/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..259148fa18f9fb7ef58563f4ff15fc7b172339fb --- /dev/null +++ b/hapsigntool_cpp/codesigning/fsverity/.gitignore @@ -0,0 +1,32 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/hapsigntool_cpp/codesigning/fsverity/include/fs_verity_descriptor.h b/hapsigntool_cpp/codesigning/fsverity/include/fs_verity_descriptor.h new file mode 100644 index 0000000000000000000000000000000000000000..2560a17f65c1a4de9945e655d621c4d05a33c5d2 --- /dev/null +++ b/hapsigntool_cpp/codesigning/fsverity/include/fs_verity_descriptor.h @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2024-2024 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_FSVERITY_DESCRIPTOR_H +#define SIGNATURETOOLS_FSVERITY_DESCRIPTOR_H + +#include +#include +#include + +#include "byte_buffer.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { +class FsVerityDescriptor { +public: + static const uint8_t VERSION = 1; + static const int PAGE_SIZE_4K = 4096; + static const int FLAG_STORE_MERKLE_TREE_OFFSET = 0x1; + static const int FS_VERITY_DESCRIPTOR_TYPE = 0x1; + static const uint8_t CODE_SIGN_VERSION = 0x1; + static const int DESCRIPTOR_SIZE = 256; + static const int ROOT_HASH_FILED_SIZE = 64; + static const int SALT_SIZE = 32; + static const int RESERVED_SIZE_AFTER_FLAGS = 4; + static const int RESERVED_SIZE_AFTER_TREE_OFFSET = 127; + + class Builder; + FsVerityDescriptor(); + long GetFileSize() + { + return fileSize; + } + + long GetMerkleTreeOffset() + { + return merkleTreeOffset; + } + + int GetSignSize() + { + return signSize; + } + + static FsVerityDescriptor FromByteArray(std::vector& bytes); + void ToByteArray(std::vector &ret); + void GetByteForGenerateDigest(std::vector& ret); + + FsVerityDescriptor(Builder& builder) + { + this->version = builder.version; + this->fileSize = builder.fileSize; + this->hashAlgorithm = builder.hashAlgorithm; + this->log2BlockSize = builder.log2BlockSize; + this->saltSize = builder.saltSize; + this->signSize = builder.signSize; + this->salt = builder.salt; + this->rawRootHash = builder.rawRootHash; + this->flags = builder.flags; + this->merkleTreeOffset = builder.merkleTreeOffset; + this->csVersion = builder.csVersion; + } + + void WriteBytesWithSize(ByteBuffer* buffer, std::vector& src, int size); + +public: +class Builder { + friend class FsVerityDescriptor; +public: + Builder& SetVersion(uint8_t version) + { + this->version = version; + return *this; + } + + Builder& SetFileSize(long fileSize) + { + this->fileSize = fileSize; + return *this; + } + + Builder& SetHashAlgorithm(uint8_t hashAlgorithm) + { + this->hashAlgorithm = hashAlgorithm; + return *this; + } + + Builder& SetLog2BlockSize(uint8_t log2BlockSize) + { + this->log2BlockSize = log2BlockSize; + return *this; + } + + Builder& SetSignSize(int signSize) + { + this->signSize = signSize; + return *this; + } + + Builder& SetSaltSize(uint8_t saltSize) + { + this->saltSize = saltSize; + return *this; + } + + Builder& SetSalt(const std::vector& salt) + { + this->salt = salt; + return *this; + } + + Builder& SetRawRootHash(const std::vector& rawRootHash) + { + this->rawRootHash = rawRootHash; + return *this; + } + + Builder& SetFlags(int flags) + { + this->flags = flags; + return *this; + } + + Builder& SetMerkleTreeOffset(long merkleTreeOffset) + { + this->merkleTreeOffset = merkleTreeOffset; + return *this; + } + + Builder& SetCsVersion(uint8_t csVersion) + { + this->csVersion = csVersion; + return *this; + } + + FsVerityDescriptor Build() + { + return FsVerityDescriptor(*this); + } + +private: + uint8_t version = VERSION; + long fileSize; + uint8_t hashAlgorithm; + uint8_t log2BlockSize; + uint8_t saltSize; + int signSize; + std::vector salt; + std::vector rawRootHash; + std::int32_t flags; + std::int64_t merkleTreeOffset; + uint8_t csVersion; +}; + +private: + uint8_t version; + long fileSize; + uint8_t hashAlgorithm; + uint8_t log2BlockSize; + uint8_t saltSize; + int signSize; + std::vector salt; + std::vector rawRootHash; + int flags; + long merkleTreeOffset; + uint8_t csVersion; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATURETOOLS_FSVERITY_DESCRIPTOR_H \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/fsverity/include/fs_verity_descriptor_with_sign.h b/hapsigntool_cpp/codesigning/fsverity/include/fs_verity_descriptor_with_sign.h new file mode 100644 index 0000000000000000000000000000000000000000..c248b0833533b89c1cafd1c379980948159daebb --- /dev/null +++ b/hapsigntool_cpp/codesigning/fsverity/include/fs_verity_descriptor_with_sign.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024-2024 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_FSVERITY_DESCRIPTOR_WITH_SIGN_H +#define SIGNATURETOOLS_FSVERITY_DESCRIPTOR_WITH_SIGN_H + +#include +#include + +#include "fs_verity_descriptor.h" + +namespace OHOS { +namespace SignatureTools { +class FsVerityDescriptorWithSign { +public: + static constexpr int32_t INTEGER_BYTES = 4; + +public: + FsVerityDescriptorWithSign(); + FsVerityDescriptorWithSign(FsVerityDescriptor fsVerityDescriptor, std::vector &signature); + FsVerityDescriptorWithSign(int32_t type, int32_t length, FsVerityDescriptor fsVerityDescriptor, + std::vector &signature); + int32_t Size(); + void ToByteArray(std::vector &ret); + FsVerityDescriptor GetFsVerityDescriptor(); + std::vector GetSignature(); + +private: + int32_t type = FsVerityDescriptor::FS_VERITY_DESCRIPTOR_TYPE;; + int32_t length; + FsVerityDescriptor fsVerityDescriptor; + std::vector signature; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATURETOOLS_FSVERITY_DIGEST_H \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/fsverity/include/fs_verity_digest.h b/hapsigntool_cpp/codesigning/fsverity/include/fs_verity_digest.h new file mode 100644 index 0000000000000000000000000000000000000000..b3469ff43a316bbca95af66fe9c6b92f7ac43bba --- /dev/null +++ b/hapsigntool_cpp/codesigning/fsverity/include/fs_verity_digest.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024-2024 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_FSVERITY_DIGEST_H +#define SIGNATURETOOLS_FSVERITY_DIGEST_H + +#include +#include +#include + +#include "byte_buffer.h" + +namespace OHOS { +namespace SignatureTools { +class FsVerityDigest { +public: + static void GetFsVerityDigest(int8_t algoID, std::vector& digest, std::vector& ret); + +private: + static const std::string FSVERITY_DIGEST_MAGIC; + static const int DIGEST_HEADER_SIZE; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATURETOOLS_FSVERITY_DIGEST_H \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/fsverity/include/fs_verity_generator.h b/hapsigntool_cpp/codesigning/fsverity/include/fs_verity_generator.h new file mode 100644 index 0000000000000000000000000000000000000000..c4668a875bdd5c4bf7d7bc15f525546c7f9e2852 --- /dev/null +++ b/hapsigntool_cpp/codesigning/fsverity/include/fs_verity_generator.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2024-2024 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_FSVERITY_GENERATOR_H +#define SIGNATURETOOLS_FSVERITY_GENERATOR_H + +#include +#include +#include + +#include "merkle_tree.h" +#include "merkle_tree_builder.h" +#include "fs_verity_descriptor.h" +#include "fs_verity_digest.h" + +namespace OHOS { +namespace SignatureTools { +class FsVerityGenerator { +public: + MerkleTree* GenerateMerkleTree(std::istream& inputStream, long size, + const FsVerityHashAlgorithm& fsVerityHashAlgorithm); + bool GenerateFsVerityDigest(std::istream& inputStream, long size, long fsvTreeOffset); + std::vector GetFsVerityDigest() + { + return fsVerityDigest; + } + + std::vector Getsalt() + { + return salt; + } + + std::vector GetTreeBytes() + { + return treeBytes; + } + + std::vector GetRootHash() + { + return rootHash; + } + + std::vector GetSalt() + { + return salt; + } + + int GetSaltSize() + { + return salt.empty() ? 0 : salt.size(); + } + + static uint8_t GetFsVerityHashAlgorithm() + { + return FS_VERITY_HASH_ALGORITHM.GetId(); + } + + static uint8_t GetLog2BlockSize() + { + return LOG_2_OF_FSVERITY_HASH_PAGE_SIZE; + } + +protected: + std::vector salt; + +private: + static const FsVerityHashAlgorithm FS_VERITY_HASH_ALGORITHM; + static const int8_t LOG_2_OF_FSVERITY_HASH_PAGE_SIZE; + std::vector fsVerityDigest; + std::vector treeBytes; + std::vector rootHash; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATURETOOLS_FSVERITY_GENERATOR_H \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/fsverity/include/fs_verity_hash_algorithm.h b/hapsigntool_cpp/codesigning/fsverity/include/fs_verity_hash_algorithm.h new file mode 100644 index 0000000000000000000000000000000000000000..90708d4ea77dc40db15a0cc57406d584aeed4193 --- /dev/null +++ b/hapsigntool_cpp/codesigning/fsverity/include/fs_verity_hash_algorithm.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024-2024 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_FSVERITY_HASH_ALGORITHM_H +#define SIGNATURETOOLS_FSVERITY_HASH_ALGORITHM_H + +#include + +namespace OHOS { +namespace SignatureTools { +class FsVerityHashAlgorithm { +public: + static const FsVerityHashAlgorithm SHA256; + static const FsVerityHashAlgorithm SHA512; + FsVerityHashAlgorithm(const uint8_t id, const std::string& hashAlgorithm, const int outputByteSize) + : id(id), hashAlgorithm(hashAlgorithm), outputByteSize(outputByteSize) + { + } + char GetId() const; + const std::string& GetHashAlgorithm() const; + int GetOutputByteSize() const; + +private: + const uint8_t id; + const std::string hashAlgorithm; + const int outputByteSize; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATURETOOLS_FSVERITY_HASH_ALGORITHM_H \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/fsverity/include/merkle_tree.h b/hapsigntool_cpp/codesigning/fsverity/include/merkle_tree.h new file mode 100644 index 0000000000000000000000000000000000000000..efec7c18ba91a94dd8872c4ac309fe111a18a562 --- /dev/null +++ b/hapsigntool_cpp/codesigning/fsverity/include/merkle_tree.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024-2024 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_MERKLE_TREE_H +#define SIGNATURETOOLS_MERKLE_TREE_H + +#include + +#include "fs_verity_hash_algorithm.h" + +namespace OHOS { +namespace SignatureTools { +class MerkleTree { +public: + MerkleTree(const std::vector& rootHash, const std::vector& tree, + const SignatureTools::FsVerityHashAlgorithm& fsVerityHashAlgorithm) + : rootHash(rootHash), + tree(tree), + fsVerityHashAlgorithm(fsVerityHashAlgorithm) + { + } + std::vector rootHash; + std::vector tree; + SignatureTools::FsVerityHashAlgorithm fsVerityHashAlgorithm; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATURETOOLS_MERKLE_TREE_H \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/fsverity/include/merkle_tree_builder.h b/hapsigntool_cpp/codesigning/fsverity/include/merkle_tree_builder.h new file mode 100644 index 0000000000000000000000000000000000000000..4cba46f70f7881d96735edf9b38377408fa2bde0 --- /dev/null +++ b/hapsigntool_cpp/codesigning/fsverity/include/merkle_tree_builder.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024-2024 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_MERKLE_TREE_BUILDER_H +#define SIGNATURETOOLS_MERKLE_TREE_BUILDER_H + +#include +#include +#include +#include +#include +#include + +#include "thread_pool.h" +#include "byte_buffer.h" +#include "merkle_tree.h" +#include "fs_digest_utils.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { +class MerkleTreeBuilder { +public: + MerkleTreeBuilder(); + MerkleTree* GenerateMerkleTree(std::istream& inputStream, long size, + const FsVerityHashAlgorithm& fsVerityHashAlgorithm); + +private: + static const int FSVERITY_HASH_PAGE_SIZE; + static const int64_t INPUTSTREAM_MAX_SIZE; + static const int CHUNK_SIZE; + static const long MAX_READ_SIZE; + static const int MAX_PROCESSORS; + static const int BLOCKINGQUEUE; + static ByteBuffer* Slice(ByteBuffer* buffer, int begin, int end); + static std::vector GetOffsetArrays(long dataSize, int digestSize); + static std::vector GetLevelSize(long dataSize, int digestSize); + static long GetChunkCount(long dataSize, long divisor); + static long GetFullChunkSize(long dataSize, long divisor, long multiplier); + void SetAlgorithm(const std::string& algorithm); + void TransInputStreamToHashData(std::istream& inputStream, long size, + ByteBuffer* outputBuffer, int bufStartIdx); + std::vector> GetDataHashes(std::istream& inputStream, long size); + + void RunHashTask(std::vector>& hashes, ByteBuffer* buffer, + int readChunkIndex, int bufStartIdx); + void TransInputDataToHashData(ByteBuffer* inputBuffer, ByteBuffer* outputBuffer, + int64_t bufStartIdx, int64_t outputStartIdx); + void GenerateHashDataByInputData(std::istream& inputStream, long size, ByteBuffer* outputBuffer, + std::vector& offsetArrays, int digestSize); + void GenerateHashDataByHashData(ByteBuffer* buffer, std::vector& offsetArrays, int digestSize); + MerkleTree* GetMerkleTree(ByteBuffer* dataBuffer, long inputDataSize, + FsVerityHashAlgorithm fsVerityHashAlgorithm); + void DataRoundupChunkSize(ByteBuffer* data, long originalDataSize, int digestSize); + bool CheckCalculateHashResult; + const int POOL_SIZE = std::min(MAX_PROCESSORS, static_cast(std::thread::hardware_concurrency())); + std::string mAlgorithm = "SHA-256"; + std::shared_ptr mPools; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATURETOOLS_MERKLE_TREE_BUILDER_H \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/fsverity/include/thread_pool.h b/hapsigntool_cpp/codesigning/fsverity/include/thread_pool.h new file mode 100644 index 0000000000000000000000000000000000000000..a995bf8d563cce769814ec31d66f40726e083ce9 --- /dev/null +++ b/hapsigntool_cpp/codesigning/fsverity/include/thread_pool.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2024-2024 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_THREAD_POOL_H +#define SIGNATRUETOOLS_THREAD_POOL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TASK_NUM (std::thread::hardware_concurrency()) + +namespace OHOS { +namespace SignatureTools { +namespace Uscript { +class ThreadPool { +public: + ThreadPool(size_t threads) + : stop(false) + { + for (size_t i = 0; i < threads; ++i) + workers.emplace_back([this] { + std::function task; + std::unique_lock lock(queue_mutex); + while (!(stop && tasks.empty())) { + condition.wait(lock, [this] { return stop || !tasks.empty(); }); + if (stop && tasks.empty()) + return; + task = std::move(tasks.front()); + tasks.pop(); + lock.unlock(); + task(); + lock.lock(); + condition_max.notify_one(); + } + }); + } + + template + auto Enqueue(F&& f, Args&& ... args) + -> std::future::type> + { + using returnType = typename std::result_of::type; + auto task = std::make_shared< std::packaged_task >( + std::bind(std::forward(f), std::forward(args)...) + ); + std::future res = task->get_future(); + { + std::unique_lock lock(queue_mutex); + // don't allow enqueueing after stopping the pool + if (stop) + throw std::runtime_error("enqueue on stopped ThreadPool"); + while (stop == false && tasks.size() >= TASK_NUM) + condition_max.wait(lock); + tasks.emplace([task] () { (*task)(); }); + condition.notify_one(); + } + return res; + } + + ~ThreadPool() + { + if (stop == false) { + { + std::unique_lock lock(queue_mutex); + stop = true; + } + condition.notify_all(); + for (std::thread& worker : workers) + worker.join(); + } + } + +private: + // need to keep track of threads so we can join them + std::vector< std::thread > workers; + // the task queue + std::queue< std::function > tasks; + // synchronization + std::mutex queue_mutex; + std::condition_variable condition; + std::condition_variable condition_max; + bool stop; +}; +} // namespace Uscript +} // namespace SignatureTools +} // namespace OHOS +#endif \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/fsverity/src/fs_verity_descriptor.cpp b/hapsigntool_cpp/codesigning/fsverity/src/fs_verity_descriptor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e1240d300cef4ba2d3cc16d7c30b4b46a1caa239 --- /dev/null +++ b/hapsigntool_cpp/codesigning/fsverity/src/fs_verity_descriptor.cpp @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2024-2024 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 "fs_verity_descriptor.h" + +namespace OHOS { +namespace SignatureTools { +FsVerityDescriptor::FsVerityDescriptor() +{} + +FsVerityDescriptor FsVerityDescriptor::FromByteArray(std::vector& bytes) +{ + std::unique_ptr bf = std::make_unique(ByteBuffer(bytes.size())); + bf->PutData(bytes.data(), bytes.size()); + // after put, rewind is mandatory before get + bf->Flip(); + std::unique_ptr builder = + std::make_unique(FsVerityDescriptor::Builder()); + int8_t inFsVersion; + bf->GetInt8(inFsVersion); + if (FsVerityDescriptor::VERSION != inFsVersion) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed data has the wrong fs-verify descriptor version in the ElfSignBlock"); + return builder->Build(); + } + int8_t inFsHashAlgorithm; + bf->GetInt8(inFsHashAlgorithm); + int8_t inLog2BlockSize; + bf->GetInt8(inLog2BlockSize); + builder->SetVersion(inFsVersion).SetHashAlgorithm(inFsHashAlgorithm).SetLog2BlockSize(inLog2BlockSize); + int8_t inSaltSize; + bf->GetInt8(inSaltSize); + int32_t inSignSize; + bf->GetInt32(inSignSize); + int64_t inDataSize; + bf->GetInt64(inDataSize); + char inRootHashArr[FsVerityDescriptor::ROOT_HASH_FILED_SIZE]; + bf->GetData(inRootHashArr, FsVerityDescriptor::ROOT_HASH_FILED_SIZE); + std::vector inRootHash(inRootHashArr, inRootHashArr + FsVerityDescriptor::ROOT_HASH_FILED_SIZE); + builder->SetSaltSize(inSaltSize).SetSignSize(inSignSize).SetFileSize(inDataSize).SetRawRootHash(inRootHash); + char inSaltArr[FsVerityDescriptor::SALT_SIZE]; + bf->GetData(inSaltArr, FsVerityDescriptor::SALT_SIZE); + std::vector inSalt(inSaltArr, inSaltArr + FsVerityDescriptor::SALT_SIZE); + int32_t inFlags; + bf->GetInt32(inFlags); + bf->SetPosition(bf->GetPosition() + RESERVED_SIZE_AFTER_FLAGS); + int64_t inTreeOffset; + bf->GetInt64(inTreeOffset); + if (inTreeOffset % PAGE_SIZE_4K != 0) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The signed data has the wrong merkle tree offset in the ElfSignBlock"); + return builder->Build(); + } + int8_t reserve[FsVerityDescriptor::RESERVED_SIZE_AFTER_TREE_OFFSET]; + bf->GetByte(reserve, sizeof(reserve)); + int8_t inCsVersion; + bf->GetInt8(inCsVersion); + builder->SetSalt(inSalt).SetFlags(inFlags).SetMerkleTreeOffset(inTreeOffset).SetCsVersion(inCsVersion); + return builder->Build(); +} + +void FsVerityDescriptor::ToByteArray(std::vector &ret) +{ + std::unique_ptr buffer = std::make_unique(ByteBuffer(DESCRIPTOR_SIZE)); + buffer->PutByte(VERSION); + buffer->PutByte(hashAlgorithm); + buffer->PutByte(log2BlockSize); + if (saltSize > SALT_SIZE) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "Salt is too long"); + ret = std::vector(); + return; + } + buffer->PutByte(saltSize); + buffer->PutInt32(signSize); + buffer->PutInt64(fileSize); + WriteBytesWithSize(buffer.get(), rawRootHash, ROOT_HASH_FILED_SIZE); + WriteBytesWithSize(buffer.get(), salt, SALT_SIZE); + buffer->PutInt32(flags); + std::vector emptyVector; + WriteBytesWithSize(buffer.get(), emptyVector, RESERVED_SIZE_AFTER_FLAGS); + buffer->PutInt64(merkleTreeOffset); + WriteBytesWithSize(buffer.get(), emptyVector, RESERVED_SIZE_AFTER_TREE_OFFSET); + buffer->PutByte(csVersion); + buffer->Flip(); + char dataArr[DESCRIPTOR_SIZE] = { 0 }; + buffer->GetData(dataArr, DESCRIPTOR_SIZE); + ret = std::vector(dataArr, dataArr + DESCRIPTOR_SIZE); + return; +} + +void FsVerityDescriptor::GetByteForGenerateDigest(std::vector &ret) +{ + std::unique_ptr buffer = std::make_unique(ByteBuffer(DESCRIPTOR_SIZE)); + buffer->PutByte(CODE_SIGN_VERSION); + buffer->PutByte(hashAlgorithm); + buffer->PutByte(log2BlockSize); + if (saltSize > SALT_SIZE) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "Salt is too long"); + ret = std::vector(); + return; + } + buffer->PutByte(saltSize); + buffer->PutInt32(0); + buffer->PutInt64(fileSize); + WriteBytesWithSize(buffer.get(), rawRootHash, ROOT_HASH_FILED_SIZE); + WriteBytesWithSize(buffer.get(), salt, SALT_SIZE); + buffer->PutInt32(flags); + std::vector emptyVector; + WriteBytesWithSize(buffer.get(), emptyVector, RESERVED_SIZE_AFTER_FLAGS); + buffer->PutInt64(merkleTreeOffset); + buffer->Flip(); + char dataArr[DESCRIPTOR_SIZE] = { 0 }; + buffer->GetData(dataArr, DESCRIPTOR_SIZE); + ret = std::vector(dataArr, dataArr + DESCRIPTOR_SIZE); + return; +} + +void FsVerityDescriptor::WriteBytesWithSize(ByteBuffer* buffer, std::vector& src, int size) +{ + int pos = buffer->GetPosition(); + if (!src.empty()) { + if (src.size() > size) { + buffer->PutData(0, src.data(), src.size()); + } else { + buffer->PutData(src.data(), src.size()); + } + } + buffer->SetPosition(pos + size); +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/fsverity/src/fs_verity_descriptor_with_sign.cpp b/hapsigntool_cpp/codesigning/fsverity/src/fs_verity_descriptor_with_sign.cpp new file mode 100644 index 0000000000000000000000000000000000000000..97b8f012f949873f709ab624502994a6718fe40e --- /dev/null +++ b/hapsigntool_cpp/codesigning/fsverity/src/fs_verity_descriptor_with_sign.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2024-2024 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 "fs_verity_descriptor_with_sign.h" + +namespace OHOS { +namespace SignatureTools { + +FsVerityDescriptorWithSign::FsVerityDescriptorWithSign() +{ +} + +FsVerityDescriptorWithSign::FsVerityDescriptorWithSign(FsVerityDescriptor fsVerityDescriptor, + std::vector &signature) +{ + this->fsVerityDescriptor = fsVerityDescriptor; + if (!signature.empty()) { + this->signature = signature; + } + length = FsVerityDescriptor::DESCRIPTOR_SIZE + this->signature.size(); +} + +FsVerityDescriptorWithSign::FsVerityDescriptorWithSign(int32_t type, int32_t length, + FsVerityDescriptor fsVerityDescriptor, std::vector &signature) +{ + this->type = type; + this->length = length; + this->fsVerityDescriptor = fsVerityDescriptor; + this->signature = signature; +} + +int32_t FsVerityDescriptorWithSign::Size() +{ + int tmpVariable = 2; + return INTEGER_BYTES * tmpVariable + FsVerityDescriptor::DESCRIPTOR_SIZE + signature.size(); +} + +void FsVerityDescriptorWithSign::ToByteArray(std::vector& ret) +{ + std::unique_ptr buffer = std::make_unique(Size()); + buffer->PutInt32(type); + buffer->PutInt32(length); + std::vector fsArr; + fsVerityDescriptor.ToByteArray(fsArr); + buffer->PutData(fsArr.data(), fsArr.size()); + buffer->PutData(signature.data(), signature.size()); + buffer->Flip(); + ret = std::vector(buffer->GetBufferPtr(), buffer->GetBufferPtr() + buffer->GetLimit()); + return; +} + +FsVerityDescriptor FsVerityDescriptorWithSign::GetFsVerityDescriptor() +{ + return fsVerityDescriptor; +} + +std::vector FsVerityDescriptorWithSign::GetSignature() +{ + return signature; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/fsverity/src/fs_verity_digest.cpp b/hapsigntool_cpp/codesigning/fsverity/src/fs_verity_digest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8d15ca017293c5fcd2d3de6262f9964cbfa0b078 --- /dev/null +++ b/hapsigntool_cpp/codesigning/fsverity/src/fs_verity_digest.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024-2024 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 "securec.h" +#include "fs_verity_digest.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { +const std::string FsVerityDigest::FSVERITY_DIGEST_MAGIC = "FSVerity"; +const int FsVerityDigest::DIGEST_HEADER_SIZE = 12; + +void FsVerityDigest::GetFsVerityDigest(int8_t algoID, std::vector& digest, + std::vector &ret) +{ + const int size = DIGEST_HEADER_SIZE + digest.size(); + if (size <= 0) { + ret = std::vector(); + return; + } + std::unique_ptr buffer = std::make_unique(ByteBuffer(size)); + buffer->PutData(FSVERITY_DIGEST_MAGIC.c_str(), (int32_t)FSVERITY_DIGEST_MAGIC.length()); + buffer->PutInt16(algoID); + buffer->PutInt16((int16_t)digest.size()); + buffer->PutData(digest.data(), digest.size()); + buffer->Flip(); + char dataArr[size]; + if (memset_s(dataArr, sizeof(dataArr), 0, sizeof(dataArr)) != RET_OK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + ret = std::vector(); + return; + } + buffer->GetData(dataArr, size); + ret = std::vector(dataArr, dataArr + size); + return; +} +} // namespace SignatureTools +} // namespace OHOS diff --git a/hapsigntool_cpp/codesigning/fsverity/src/fs_verity_generator.cpp b/hapsigntool_cpp/codesigning/fsverity/src/fs_verity_generator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f69c303c523dc0897bcdb01d91942e9347489bd8 --- /dev/null +++ b/hapsigntool_cpp/codesigning/fsverity/src/fs_verity_generator.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2024-2024 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 "fs_verity_generator.h" + +namespace OHOS { +namespace SignatureTools { +const FsVerityHashAlgorithm FS_SHA256(1, "SHA-256", 256 / 8); +const FsVerityHashAlgorithm FS_SHA512(2, "SHA-512", 512 / 8); +const int8_t FsVerityGenerator::LOG_2_OF_FSVERITY_HASH_PAGE_SIZE = 12; +const FsVerityHashAlgorithm FsVerityGenerator::FS_VERITY_HASH_ALGORITHM = FS_SHA256; + +MerkleTree* FsVerityGenerator::GenerateMerkleTree(std::istream& inputStream, long size, + const FsVerityHashAlgorithm& fsVerityHashAlgorithm) +{ + std::unique_ptrbuilder = std::make_unique(MerkleTreeBuilder()); + return builder->GenerateMerkleTree(inputStream, size, fsVerityHashAlgorithm); +} + +bool FsVerityGenerator::GenerateFsVerityDigest(std::istream& inputStream, long size, long fsvTreeOffset) +{ + std::vector emptyVector; + MerkleTree* merkleTree = nullptr; + if (size == 0) { + merkleTree = new MerkleTree(emptyVector, emptyVector, FS_SHA256); + } else { + merkleTree = GenerateMerkleTree(inputStream, size, FS_SHA256); + } + if (nullptr == merkleTree) { + return false; + } + int flags = fsvTreeOffset == 0 ? 0 : FsVerityDescriptor::FLAG_STORE_MERKLE_TREE_OFFSET; + std::shared_ptr merkleTree_ptr(merkleTree); + // sign size is 0, cs version is 0 + std::unique_ptr builder = std::make_unique(); + builder->SetFileSize(size) + .SetHashAlgorithm(FS_SHA256.GetId()) + .SetLog2BlockSize(LOG_2_OF_FSVERITY_HASH_PAGE_SIZE) + .SetSaltSize((uint8_t)GetSaltSize()) + .SetSalt(salt) + .SetRawRootHash(merkleTree_ptr->rootHash) + .SetFlags(flags) + .SetMerkleTreeOffset(fsvTreeOffset); + std::vector fsVerityDescriptor; + builder->Build().GetByteForGenerateDigest(fsVerityDescriptor); + std::vector digest; + DigestUtils digestUtils(HASH_SHA256); + std::stringstream ss; + for (const auto& elem : fsVerityDescriptor) { + ss << elem; + } + digestUtils.AddData(ss.str()); + std::string result = digestUtils.Result(DigestUtils::Type::BINARY); + for (int i = 0; i < result.size(); i++) { + digest.push_back(result[i]); + } + FsVerityDigest::GetFsVerityDigest(FS_SHA256.GetId(), digest, fsVerityDigest); + treeBytes = merkleTree_ptr->tree; + rootHash = merkleTree_ptr->rootHash; + return true; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/fsverity/src/fs_verity_hash_algorithm.cpp b/hapsigntool_cpp/codesigning/fsverity/src/fs_verity_hash_algorithm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..47d659121dfdbce726310c253ce7a01f2c33b8b9 --- /dev/null +++ b/hapsigntool_cpp/codesigning/fsverity/src/fs_verity_hash_algorithm.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024-2024 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 "fs_verity_hash_algorithm.h" + +namespace OHOS { +namespace SignatureTools { +const FsVerityHashAlgorithm FsVerityHashAlgorithm::SHA256((char)1, "SHA-256", 256 / 8); +const FsVerityHashAlgorithm FsVerityHashAlgorithm::SHA512((char)2, "SHA-512", 512 / 8); + +char FsVerityHashAlgorithm::GetId() const +{ + return id; +} + +const std::string& FsVerityHashAlgorithm::GetHashAlgorithm() const +{ + return hashAlgorithm; +} + +int FsVerityHashAlgorithm::GetOutputByteSize() const +{ + return outputByteSize; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/fsverity/src/merkle_tree_builder.cpp b/hapsigntool_cpp/codesigning/fsverity/src/merkle_tree_builder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..82c60011d6c414ae04c12c5db62e917fba50318d --- /dev/null +++ b/hapsigntool_cpp/codesigning/fsverity/src/merkle_tree_builder.cpp @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2024-2024 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 "merkle_tree_builder.h" + +using namespace OHOS::SignatureTools; +using namespace OHOS::SignatureTools::Uscript; +const int MerkleTreeBuilder::FSVERITY_HASH_PAGE_SIZE = 4096; +const int64_t MerkleTreeBuilder::INPUTSTREAM_MAX_SIZE = 4503599627370496L; +const int MerkleTreeBuilder::CHUNK_SIZE = 4096; +const long MerkleTreeBuilder::MAX_READ_SIZE = 4194304L; +const int MerkleTreeBuilder::MAX_PROCESSORS = 32; +const int MerkleTreeBuilder::BLOCKINGQUEUE = 4; + +void MerkleTreeBuilder::SetAlgorithm(const std::string& algorithm) +{ + mAlgorithm = algorithm; +} + +void MerkleTreeBuilder::TransInputStreamToHashData(std::istream& inputStream, + long size, ByteBuffer* outputBuffer, int bufStartIdx) +{ + if (size == 0 || static_cast(size) > INPUTSTREAM_MAX_SIZE) { + SIGNATURE_TOOLS_LOGE("invalid input stream size"); + CheckCalculateHashResult = false; + return; + } + std::vector> hashes = GetDataHashes(inputStream, size); + int32_t writeSize = 0; + for (const auto& hash : hashes) { + outputBuffer->PutData(writeSize + bufStartIdx, hash.data(), hash.size()); + writeSize += hash.size(); + } + outputBuffer->SetLimit(outputBuffer->GetCapacity() - bufStartIdx); + outputBuffer->SetCapacity(outputBuffer->GetCapacity() - bufStartIdx); + outputBuffer->SetPosition(writeSize); +} + +std::vector> MerkleTreeBuilder::GetDataHashes(std::istream& inputStream, long size) +{ + int count = (int)(GetChunkCount(size, MAX_READ_SIZE)); + int chunks = (int)(GetChunkCount(size, CHUNK_SIZE)); + std::vector> hashes(chunks); + std::vector> thread_results; + long readOffset = 0L; + for (int i = 0; i < count; i++) { + long readLimit = std::min(readOffset + MAX_READ_SIZE, size); + int readSize = (int)((readLimit - readOffset)); + int fullChunkSize = (int)(GetFullChunkSize(readSize, CHUNK_SIZE, CHUNK_SIZE)); + ByteBuffer* byteBuffer(new ByteBuffer(fullChunkSize)); + std::vector buffer(CHUNK_SIZE); + int num = 0; + int offset = 0; + int flag = 0; + int len = CHUNK_SIZE; + while (num > 0 || flag == 0) { + inputStream.read((buffer.data()), len); + if (inputStream.fail() && !inputStream.eof()) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "Error occurred while reading data"); + CheckCalculateHashResult = false; + return std::vector>(); + } + num = inputStream.gcount(); + byteBuffer->PutData(buffer.data(), num); + offset += num; + len = std::min(CHUNK_SIZE, readSize - offset); + if (len <= 0 || offset == readSize) { + break; + } + flag = 1; + } + if (offset != readSize) { + PrintErrorNumberMsg("READ_FILE_ERROR", IO_ERROR, "Error reading buffer from input"); + CheckCalculateHashResult = false; + return std::vector>(); + } + byteBuffer->Flip(); + int readChunkIndex = (int)(GetFullChunkSize(MAX_READ_SIZE, CHUNK_SIZE, i)); + thread_results.push_back(mPools->Enqueue(&MerkleTreeBuilder::RunHashTask, this, std::ref(hashes), + byteBuffer, readChunkIndex, 0)); + readOffset += readSize; + } + for (auto& thread_result : thread_results) { + thread_result.wait(); + } + return hashes; +} + +ByteBuffer* MerkleTreeBuilder::Slice(ByteBuffer* buffer, int begin, int end) +{ + ByteBuffer* tmpBuffer = buffer->Duplicate(); + tmpBuffer->SetPosition(0); + tmpBuffer->SetLimit(end); + tmpBuffer->SetPosition(begin); + return &tmpBuffer->slice_for_codesigning(); +} + +std::vector MerkleTreeBuilder::GetOffsetArrays(long dataSize, int digestSize) +{ + std::vector levelSize = GetLevelSize(dataSize, digestSize); + std::vector levelOffset(levelSize.size() + 1); + levelOffset[0] = 0; + for (int i = 0; i < levelSize.size(); i++) { + levelOffset[i + 1] = levelOffset[i] + levelSize[levelSize.size() - i - 1]; + } + return levelOffset; +} + +std::vector MerkleTreeBuilder::GetLevelSize(long dataSize, int digestSize) +{ + std::vector levelSize; + + long fullChunkSize = 0L; + long originalDataSize = dataSize; + do { + fullChunkSize = GetFullChunkSize(originalDataSize, CHUNK_SIZE, digestSize); + int size = GetFullChunkSize(fullChunkSize, CHUNK_SIZE, CHUNK_SIZE); + levelSize.push_back(size); + originalDataSize = fullChunkSize; + } while (fullChunkSize > CHUNK_SIZE); + return levelSize; +} + +void MerkleTreeBuilder::RunHashTask(std::vector>& hashes, + ByteBuffer* buffer, int readChunkIndex, int bufStartIdx) +{ + int offset = 0; + + std::shared_ptr bufferPtr(buffer); + int bufferSize = bufferPtr->GetCapacity(); + int index = readChunkIndex; + while (offset < bufferSize) { + ByteBuffer* chunk = Slice(bufferPtr.get(), offset, offset + CHUNK_SIZE); + std::vector tmpByte(CHUNK_SIZE); + chunk->GetData(offset + bufStartIdx, tmpByte.data(), CHUNK_SIZE); + DigestUtils digestUtils(HASH_SHA256); + std::string tmpByteStr(tmpByte.begin(), tmpByte.end()); + digestUtils.AddData(tmpByteStr); + std::string result = digestUtils.Result(DigestUtils::Type::BINARY); + std::vector hashEle; + for (int i = 0; i < result.size(); i++) { + hashEle.push_back(result[i]); + } + hashes[index++] = hashEle; + offset += CHUNK_SIZE; + delete chunk; + } +} + +void MerkleTreeBuilder::TransInputDataToHashData(ByteBuffer* inputBuffer, ByteBuffer* outputBuffer, + int64_t inputStartIdx, int64_t outputStartIdx) +{ + long size = inputBuffer->GetCapacity(); + int chunks = (int)GetChunkCount(size, CHUNK_SIZE); + std::vector> hashes(chunks); + long readOffset = 0L; + int startChunkIndex = 0; + while (readOffset < size) { + long readLimit = std::min(readOffset + MAX_READ_SIZE, size); + ByteBuffer* buffer = Slice(inputBuffer, (int)readOffset, (int)readLimit); + buffer->SetPosition(0); + int readChunkIndex = startChunkIndex; + RunHashTask(hashes, buffer, readChunkIndex, inputStartIdx); + int readSize = (int)(readLimit - readOffset); + startChunkIndex += (int)GetChunkCount(readSize, CHUNK_SIZE); + readOffset += readSize; + inputStartIdx += readSize; + } + int32_t writeSize = 0; + for (const auto& hash : hashes) { + outputBuffer->PutData(writeSize + outputStartIdx, hash.data(), hash.size()); + writeSize += hash.size(); + } +} + +OHOS::SignatureTools::MerkleTreeBuilder::MerkleTreeBuilder() :mPools(new Uscript::ThreadPool(POOL_SIZE)) +{ + CheckCalculateHashResult = true; +} + +MerkleTree* MerkleTreeBuilder::GenerateMerkleTree(std::istream& inputStream, long size, + const FsVerityHashAlgorithm& fsVerityHashAlgorithm) +{ + SetAlgorithm(fsVerityHashAlgorithm.GetHashAlgorithm()); + int digestSize = fsVerityHashAlgorithm.GetOutputByteSize(); + std::vector offsetArrays = GetOffsetArrays(size, digestSize); + std::unique_ptr allHashBuffer = std::make_unique + (ByteBuffer(offsetArrays[offsetArrays.size() - 1])); + GenerateHashDataByInputData(inputStream, size, allHashBuffer.get(), offsetArrays, digestSize); + GenerateHashDataByHashData(allHashBuffer.get(), offsetArrays, digestSize); + + if (CheckCalculateHashResult) { + return GetMerkleTree(allHashBuffer.get(), size, fsVerityHashAlgorithm); + } + return nullptr; +} + +void MerkleTreeBuilder::GenerateHashDataByInputData(std::istream& inputStream, long size, ByteBuffer* outputBuffer, + std::vector& offsetArrays, int digestSize) +{ + int64_t inputDataOffsetBegin = offsetArrays[offsetArrays.size() - 2]; + int64_t inputDataOffsetEnd = offsetArrays[offsetArrays.size() - 1]; + ByteBuffer* hashBuffer = Slice(outputBuffer, 0, inputDataOffsetEnd); + TransInputStreamToHashData(inputStream, size, hashBuffer, inputDataOffsetBegin); + DataRoundupChunkSize(hashBuffer, size, digestSize); + delete hashBuffer; +} + +void MerkleTreeBuilder::GenerateHashDataByHashData(ByteBuffer* buffer, + std::vector& offsetArrays, int digestSize) +{ + for (int i = offsetArrays.size() - 3; i >= 0; i--) { + int64_t generateOffset = offsetArrays[i]; + int64_t originalOffset = offsetArrays[i + 1]; + ByteBuffer* generateHashBuffer = Slice(buffer, offsetArrays[i], offsetArrays[i + 1] + offsetArrays[i]); + ByteBuffer* readOnlyBuffer = buffer->Duplicate(); + ByteBuffer* originalHashBuffer = Slice(readOnlyBuffer, offsetArrays[i + 1], offsetArrays[i + 2]); + TransInputDataToHashData(originalHashBuffer, generateHashBuffer, originalOffset, generateOffset); + DataRoundupChunkSize(generateHashBuffer, originalHashBuffer->GetCapacity(), digestSize); + delete originalHashBuffer; + delete readOnlyBuffer; + delete generateHashBuffer; + } +} + +MerkleTree* MerkleTreeBuilder::GetMerkleTree(ByteBuffer* dataBuffer, long inputDataSize, + FsVerityHashAlgorithm fsVerityHashAlgorithm) +{ + int digestSize = fsVerityHashAlgorithm.GetOutputByteSize(); + dataBuffer->Flip(); + std::vector rootHash; + std::vector tree; + if (inputDataSize < FSVERITY_HASH_PAGE_SIZE) { + ByteBuffer* fsVerityHashPageBuffer = Slice(dataBuffer, 0, digestSize); + rootHash = std::vector(digestSize); + fsVerityHashPageBuffer->GetByte((int8_t*)rootHash.data(), digestSize); + if (fsVerityHashPageBuffer != nullptr) { + delete fsVerityHashPageBuffer; + fsVerityHashPageBuffer = nullptr; + } + } else { + tree = std::vector(dataBuffer->GetBufferPtr(), dataBuffer->GetBufferPtr() + dataBuffer->GetCapacity()); + ByteBuffer* fsVerityHashPageBuffer = Slice(dataBuffer, 0, FSVERITY_HASH_PAGE_SIZE); + std::vector fsVerityHashPage(FSVERITY_HASH_PAGE_SIZE); + fsVerityHashPageBuffer->GetData(0, fsVerityHashPage.data(), FSVERITY_HASH_PAGE_SIZE); + DigestUtils digestUtils(HASH_SHA256); + std::string fsVerityHashPageStr(fsVerityHashPage.begin(), fsVerityHashPage.end()); + digestUtils.AddData(fsVerityHashPageStr); + std::string result = digestUtils.Result(DigestUtils::Type::BINARY); + for (int i = 0; i < static_cast(result.size()); i++) { + rootHash.push_back(result[i]); + } + if (fsVerityHashPageBuffer != nullptr) { + delete fsVerityHashPageBuffer; + fsVerityHashPageBuffer = nullptr; + } + } + + return new MerkleTree(rootHash, tree, fsVerityHashAlgorithm); +} + +void MerkleTreeBuilder::DataRoundupChunkSize(ByteBuffer* data, long originalDataSize, int digestSize) +{ + long fullChunkSize = GetFullChunkSize(originalDataSize, CHUNK_SIZE, digestSize); + int diffValue = (int)(fullChunkSize % CHUNK_SIZE); + if (diffValue > 0) { + std::vector padding(CHUNK_SIZE - diffValue); + data->SetPosition(data->GetPosition() + (CHUNK_SIZE - diffValue)); + } +} + +long MerkleTreeBuilder::GetChunkCount(long dataSize, long divisor) +{ + return (long)std::ceil((double)dataSize / (double)divisor); +} + +long MerkleTreeBuilder::GetFullChunkSize(long dataSize, long divisor, long multiplier) +{ + return GetChunkCount(dataSize, divisor) * multiplier; +} \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/sign/include/bc_signeddata_generator.h b/hapsigntool_cpp/codesigning/sign/include/bc_signeddata_generator.h new file mode 100644 index 0000000000000000000000000000000000000000..79d115aa1e2ed8a1f9cb54634d2d682192d53526 --- /dev/null +++ b/hapsigntool_cpp/codesigning/sign/include/bc_signeddata_generator.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024-2024 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_SIGNEDDATA_GENERATOR_H +#define SIGNATRUETOOLS_BC_SIGNEDDATA_GENERATOR_H + +#include +#include +#include + +#include "openssl/x509.h" +#include "signeddata_generator.h" +#include "pkcs7_data.h" +#include "signer_config.h" +#include "signer.h" + +namespace OHOS { +namespace SignatureTools { + +class BCSignedDataGenerator : public SignedDataGenerator { +public: + /** + * Generate signature data with specific content and sign configuration. + * + * @param content unsigned file digest content. + * @param signerConfig sign configurations. + * @ret signed data. + * @return 0:success <0:error + */ + static int GetSigAlg(SignerConfig* signerConfig, std::string& sigAlg); + int GenerateSignedData(const std::string& content, SignerConfig* signerConfig, std::string& ret)override; + void SetOwnerId(const std::string& ownerID); + +private: + // @return 0(NID_undef) >0: success(new NID) + static int CreateNIDFromOID(const std::string& oid, const std::string& shortName, + const std::string& longName); + int PackageSignedData(const std::string& content, std::shared_ptr signer, + const std::string& sigAlg, std::string& ret); + // @return 0:success <0 :error + int AddOwnerID(std::vector& attrs, const std::string& ownerID); + +private: + std::string m_ownerID; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_BC_SIGNEDDATA_GENERATOR_H \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/sign/include/code_signing.h b/hapsigntool_cpp/codesigning/sign/include/code_signing.h new file mode 100644 index 0000000000000000000000000000000000000000..6c8f3bcdfc7322b1740af9f5bed0815c004b23d5 --- /dev/null +++ b/hapsigntool_cpp/codesigning/sign/include/code_signing.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2024-2024 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_CODE_SIGNING_H +#define SIGNATURETOOLS_CODE_SIGNING_H + +#include +#include +#include + +#include "securec.h" +#include "hap_utils.h" +#include "zip_signer.h" +#include "file_utils.h" +#include "local_signer.h" +#include "signer_config.h" +#include "signature_tools_log.h" +#include "fs_verity_generator.h" +#include "merkle_tree_extension.h" +#include "bc_signeddata_generator.h" +#include "unzip_handle_param.h" +#include "code_sign_block.h" + +namespace OHOS { +namespace SignatureTools { +class CodeSigning { +public: + static const std::vector SUPPORT_FILE_FORM; + static const std::string HAP_SIGNATURE_ENTRY_NAME; + static const std::string ENABLE_SIGN_CODE_VALUE; + static const std::string LIBS_PATH_PREFIX; + CodeSigning(SignerConfig* signConfig); + CodeSigning(); + + bool SignFile(std::istream& inputStream, + int64_t fileSize, bool storeTree, + int64_t fsvTreeOffset, std::string ownerID, + std::pair>& ret); + bool GetCodeSignBlock(const std::string input, int64_t offset, + std::string inForm, std::string profileContent, + ZipSigner& zip, std::vector& ret); + bool GetElfCodeSignBlock(std::string input, int64_t offset, + std::string inForm, std::string profileContent, + std::vector &codesignData); + +public: + const std::string NATIVE_LIB_AN_SUFFIX = ".an"; + const std::string NATIVE_LIB_SO_SUFFIX = ".so"; + static bool IsNativeFile(std::string& input); + uint32_t ComputeDataSize(ZipSigner& zip); + int64_t GetTimestamp(); + bool SignNativeLibs(std::string input, std::string ownerID); + void UpdateCodeSignBlock(); + bool GetNativeEntriesFromHap(std::string& packageName, UnzipHandleParam& param); + bool GenerateSignature(std::vector& signedData, const std::string&, + std::vector&); + int64_t m_timestamp = 0; + std::vector m_extractedNativeLibSuffixs; + SignerConfig* m_signConfig; + CodeSignBlock m_codeSignBlock; + +private: + static bool CheckUnzParam(unzFile& zFile, unz_file_info& zFileInfo, char fileName[], size_t* nameLen); + static bool CheckFileName(unzFile& zFile, char fileName[], size_t* nameLen); + bool HandleZipGlobalInfo(unzFile& zFile, unz_global_info& zGlobalInfo, UnzipHandleParam& param); + bool DoNativeLibSignOrVerify(std::string fileName, std::stringbuf& sb, + UnzipHandleParam& param, int readFileSize); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATURETOOLS_CODE_SIGNING_H \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/sign/include/signeddata_generator.h b/hapsigntool_cpp/codesigning/sign/include/signeddata_generator.h new file mode 100644 index 0000000000000000000000000000000000000000..3aa11291511eb23122dc478bf18758d34559eb92 --- /dev/null +++ b/hapsigntool_cpp/codesigning/sign/include/signeddata_generator.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024-2024 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_SIGNEDDATA_GENERATOR_H +#define SIGNATRUETOOLS_SIGNEDDATA_GENERATOR_H + +#include + +#include "signer_config.h" + +namespace OHOS { +namespace SignatureTools { + +class SignedDataGenerator { +public: + virtual ~SignedDataGenerator() = default; + /** + * Generate signature data with specific content and sign configuration. + * + * @param content unsigned file digest content. + * @param signerConfig sign configurations. + * @param ret 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_SIGNEDDATA_GENERATOR_H \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/sign/include/verify_code_signature.h b/hapsigntool_cpp/codesigning/sign/include/verify_code_signature.h new file mode 100644 index 0000000000000000000000000000000000000000..7143c3bc7aaf455c649e7fa16222baf43acdc598 --- /dev/null +++ b/hapsigntool_cpp/codesigning/sign/include/verify_code_signature.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024-2024 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_VERIFY_CODE_SIGNATURE_H +#define SIGNATURETOOLS_VERIFY_CODE_SIGNATURE_H + +#include +#include +#include +#include + +#include "signature_tools_log.h" +#include "code_sign_block.h" +#include "hap_utils.h" +#include "merkle_tree_extension.h" +#include "native_lib_info_segment.h" +#include "code_signing.h" +#include "fs_verity_generator.h" +#include "cms_utils.h" + +namespace OHOS { +namespace SignatureTools { +class VerifyCodeSignature { +public: + static bool VerifyHap(std::string file, int64_t offset, int64_t length, + std::string fileFormat, std::string profileContent); + static bool VerifyElf(std::string file, int64_t offset, int64_t length, + std::string fileFormat, std::string profileContent); + static bool VerifyNativeLib(CodeSignBlock& csb, std::string& file, unzFile& zFile, + std::pair& pairResult); + static bool VerifyCodeSign(std::string file, std::pair& pairResult, CodeSignBlock& csb); + static bool VerifySingleFile(std::istream& input, int64_t length, std::vector signature, + int64_t merkleTreeOffset, std::vector inMerkleTreeBytes); + static bool AreVectorsEqual(const std::vector& vec1, const std::vector& vec2); + +private: + static bool GenerateCodeSignBlock(const std::string& file, int64_t offset, int64_t length, + CodeSignBlock& csb); + static bool ParseSegmentHead(CodeSignBlock& csb, std::ifstream& signedHap, + std::vector& merkleTreeBytes, int32_t& fileReadOffset); + static bool ParseMerkleTree(CodeSignBlock& csb, int32_t readOffset, std::ifstream& signedHap, + int64_t computedTreeOffset); + static int64_t GetAlignmentAddr(int64_t alignment, int64_t input); + static std::pair, std::vector> GenerateFsVerityDigest(std::istream& inputStream, + int64_t size, + int64_t merkleTreeOffset); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATURETOOLS_CMS_UTILS_H \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/sign/src/bc_signeddata_generator.cpp b/hapsigntool_cpp/codesigning/sign/src/bc_signeddata_generator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..43df82991bfb64e21eff21e05ef2d1a79cdb1300 --- /dev/null +++ b/hapsigntool_cpp/codesigning/sign/src/bc_signeddata_generator.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2024-2024 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 "pkcs7_data.h" +#include "local_signer.h" +#include "signer_config.h" +#include "signature_tools_log.h" +#include "signature_algorithm_helper.h" +#include "signature_tools_errno.h" +#include "bc_signeddata_generator.h" + +namespace OHOS { +namespace SignatureTools { + +int BCSignedDataGenerator::GenerateSignedData(const std::string& content, + SignerConfig* signerConfig, std::string& ret) +{ + std::string sigAlg; + int result = RET_OK; + 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) { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, + "signer is NULL"); + return INVALIDPARAM_ERROR; + } + result = GetSigAlg(signerConfig, sigAlg); + if (result < 0) { + SIGNATURE_TOOLS_LOGE("get sign algorithm from signerConfig failed"); + return INVALIDPARAM_ERROR; + } + result = PackageSignedData(content, signer, sigAlg, ret); + if (result < 0) { + SIGNATURE_TOOLS_LOGE("package signed data failed"); + return result; + } + return result; +} + +void BCSignedDataGenerator::SetOwnerId(const std::string& ownerID) +{ + m_ownerID = ownerID; +} + +int BCSignedDataGenerator::PackageSignedData(const std::string& content, + std::shared_ptr signer, + const std::string& sigAlg, std::string& ret) +{ + int result = RET_OK; + PKCS7Data p7Data(PKCS7_DETACHED_FLAGS); + std::vector attrs; + if (m_ownerID.empty() == false) { + if (AddOwnerID(attrs, m_ownerID) < 0) { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, + "create ownerIDOid failed"); + return INVALIDPARAM_ERROR; + } + } + // Generate PKCS#7 + result = p7Data.Sign(content, signer, sigAlg, ret, attrs); + if (result < 0) { + SIGNATURE_TOOLS_LOGE("generate pkcs7 signed data block failed"); + return SIGN_ERROR; + } + // Verify after parsing + result = p7Data.Parse(ret); + if (result < 0) { + SIGNATURE_TOOLS_LOGE("verify pkcs7 signed data block bytes failed"); + return PARSE_ERROR; + } + result = p7Data.Verify(content); + if (result < 0) { + SIGNATURE_TOOLS_LOGE("verify pkcs7 signed data block failed"); + return VERIFY_ERROR; + } + return result; +} + +int BCSignedDataGenerator::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; +} + +int BCSignedDataGenerator::CreateNIDFromOID(const std::string& oid, const std::string& shortName, + const std::string& longName) +{ + int nid = OBJ_txt2nid(oid.c_str()); + if (nid == NID_undef) { + nid = OBJ_create(oid.c_str(), shortName.c_str(), longName.c_str()); + } + return nid; +} + +int BCSignedDataGenerator::AddOwnerID(std::vector& attrs, const std::string& ownerID) +{ + PKCS7Attr attr; + int nid = CreateNIDFromOID(OWNERID_OID, OWNERID_OID_SHORT_NAME, OWNERID_OID_LONG_NAME); + if (nid == NID_undef) { + return RET_FAILED; + } + ASN1_STRING* ownerIDAsn1 = ASN1_STRING_new(); + if (ownerIDAsn1 == NULL) { + SIGNATURE_TOOLS_LOGE("asn1 string create error!\n"); + return RET_FAILED; + } + ASN1_STRING_set(ownerIDAsn1, ownerID.c_str(), ownerID.length()); + attr.nid = nid; + attr.atrtype = V_ASN1_UTF8STRING; + attr.value = ownerIDAsn1; + attrs.push_back(attr); + return RET_OK; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/sign/src/code_signing.cpp b/hapsigntool_cpp/codesigning/sign/src/code_signing.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7033053ad5318fa1814f27502a3a0f6e13743b07 --- /dev/null +++ b/hapsigntool_cpp/codesigning/sign/src/code_signing.cpp @@ -0,0 +1,473 @@ +/* + * Copyright (c) 2024-2024 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 "elf_sign_block.h" +#include "fs_verity_descriptor.h" +#include "fs_verity_descriptor_with_sign.h" +#include "verify_code_signature.h" +#include "code_signing.h" + +namespace OHOS { +namespace SignatureTools { +const int BUFFER_SIZE = 16 * 1024; +const int FILE_NAME_SIZE = 512; +const std::vector CodeSigning::SUPPORT_FILE_FORM = { "hap", "hsp", "hqf" }; +const std::string CodeSigning::HAP_SIGNATURE_ENTRY_NAME = "Hap"; +const std::string CodeSigning::ENABLE_SIGN_CODE_VALUE = "1"; +const std::string CodeSigning::LIBS_PATH_PREFIX = "libs/"; + +const FsVerityHashAlgorithm FS_SHA256(1, "SHA-256", 256 / 8); +const FsVerityHashAlgorithm FS_SHA512(2, "SHA-512", 512 / 8); +const int8_t LOG_2_OF_FSVERITY_HASH_PAGE_SIZE = 12; + +CodeSigning::CodeSigning(SignerConfig* signConfig) +{ + m_signConfig = signConfig; +} + +CodeSigning::CodeSigning() +{ +} + +bool CodeSigning::GetCodeSignBlock(const std::string input, int64_t offset, + std::string inForm, std::string profileContent, + ZipSigner& zip, std::vector& ret) +{ + SIGNATURE_TOOLS_LOGI("Start to sign code."); + bool formatFlag = std::find(SUPPORT_FILE_FORM.begin(), SUPPORT_FILE_FORM.end(), inForm) + == SUPPORT_FILE_FORM.end(); + if (formatFlag) { + SIGNATURE_TOOLS_LOGE("only support format is [hap, hqf, hsp, app]"); + return false; + } + uint32_t dataSize = ComputeDataSize(zip); + if (dataSize < 0) { + return false; + } + m_timestamp = GetTimestamp(); + int64_t fsvTreeOffset = m_codeSignBlock.ComputeMerkleTreeOffset(offset); + std::unique_ptr fsVerityInfoSegment = + std::make_unique((int8_t)FsVerityDescriptor::VERSION, + (int8_t)FsVerityGenerator::GetFsVerityHashAlgorithm(), + (int8_t)FsVerityGenerator::GetLog2BlockSize()); + m_codeSignBlock.SetFsVerityInfoSegment(*(fsVerityInfoSegment.get())); + SIGNATURE_TOOLS_LOGI("Sign hap."); + std::string ownerID = HapUtils::GetAppIdentifier(profileContent); + std::ifstream inputStream; + inputStream.open(input, std::ios::binary); + if (!inputStream.is_open()) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open file: " + input + "failed"); + inputStream.close(); + return false; + } + std::pair> hapSignInfoAndMerkleTreeBytesPair; + bool signFileFlag = SignFile(inputStream, dataSize, true, fsvTreeOffset, ownerID, + hapSignInfoAndMerkleTreeBytesPair); + if (!signFileFlag) { + SIGNATURE_TOOLS_LOGE("SignFile Failed"); + inputStream.close(); + return false; + } + inputStream.close(); + m_codeSignBlock.GetHapInfoSegment().SetSignInfo(hapSignInfoAndMerkleTreeBytesPair.first); + m_codeSignBlock.AddOneMerkleTree(HAP_SIGNATURE_ENTRY_NAME, + hapSignInfoAndMerkleTreeBytesPair.second); + SignNativeLibs(input, ownerID); + UpdateCodeSignBlock(); + m_codeSignBlock.GenerateCodeSignBlockByte(fsvTreeOffset, ret); + SIGNATURE_TOOLS_LOGI("Sign successfully."); + return true; +} + +uint32_t CodeSigning::ComputeDataSize(ZipSigner& zip) +{ + uint32_t dataSize = 0L; + for (const auto& entry : zip.GetZipEntries()) { + ZipEntryHeader* zipEntryHeader = entry->GetZipEntryData()->GetZipEntryHeader(); + bool runnableFileFlag = FileUtils::IsRunnableFile(zipEntryHeader->GetFileName()) + && zipEntryHeader->GetMethod() == ZipSigner::FILE_UNCOMPRESS_METHOD_FLAG; + if (runnableFileFlag) { + continue; + } + // if the first file is not uncompressed abc or so, set dataSize to zero + if (entry->GetCentralDirectory()->GetOffset() == 0) { + break; + } + // the first entry which is not abc/so/an is found, return its data offset + dataSize = entry->GetCentralDirectory()->GetOffset() + ZipEntryHeader::HEADER_LENGTH + + zipEntryHeader->GetFileNameLength() + zipEntryHeader->GetExtraLength(); + break; + } + if ((dataSize % CodeSignBlock::PAGE_SIZE_4K) != 0) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "Invalid dataSize, the dataSize is not an integer multiple of 4096"); + return -1; + } + return dataSize; +} + +int64_t CodeSigning::GetTimestamp() +{ + auto now = std::chrono::system_clock::now(); + auto nowSeconds = std::chrono::time_point_cast(now); + return nowSeconds.time_since_epoch().count(); +} + +bool CodeSigning::SignFile(std::istream& inputStream, int64_t fileSize, bool storeTree, + int64_t fsvTreeOffset, std::string ownerID, std::pair>& ret) +{ + std::unique_ptr fsVerityGenerator = + std::make_unique(); + if (!fsVerityGenerator->GenerateFsVerityDigest(inputStream, fileSize, fsvTreeOffset)) { + SIGNATURE_TOOLS_LOGE("SignFile GenerateFsVerityDigest Fail"); + return false; + } + std::vector fsVerityDigest = fsVerityGenerator->GetFsVerityDigest(); + std::vector signature; + bool generateSignatureFlag = GenerateSignature(fsVerityDigest, ownerID, signature); + if (!generateSignatureFlag) { + SIGNATURE_TOOLS_LOGE("SignFile GenerateSignature Fail"); + return false; + } + int flags = 0; + if (storeTree) { + flags = SignInfo::FLAG_MERKLE_TREE_INCLUDED; + } + int saltSize = fsVerityGenerator->GetSaltSize(); + std::vector salt = fsVerityGenerator->GetSalt(); + SignInfo signInfo(saltSize, flags, fileSize, salt, signature); + // if store merkle tree in sign info + if (storeTree) { + int merkleTreeSize = fsVerityGenerator->GetTreeBytes().empty() ? 0 + : fsVerityGenerator->GetTreeBytes().size(); + MerkleTreeExtension* merkleTreeExtension = new MerkleTreeExtension(merkleTreeSize, + fsvTreeOffset, + fsVerityGenerator->GetRootHash()); + signInfo.AddExtension(merkleTreeExtension); + } + ret = std::make_pair(signInfo, fsVerityGenerator->GetTreeBytes()); + return true; +} + +bool CodeSigning::GetElfCodeSignBlock(std::string input, int64_t offset, + std::string inForm, std::string profileContent, + std::vector& codesignData) +{ + SIGNATURE_TOOLS_LOGI("Start to sign elf code."); + int paddingSize = ElfSignBlock::ComputeMerkleTreePaddingLength(offset); + int64_t fsvTreeOffset = offset + FsVerityDescriptorWithSign::INTEGER_BYTES * 2 + paddingSize; + std::ifstream inputstream(input, std::ios::binary | std::ios::ate); + if (!inputstream.is_open()) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open file: " + input + "failed"); + return false; + } + std::streamsize fileSize = inputstream.tellg(); + inputstream.seekg(0, std::ios::beg); + std::unique_ptr fsVerityGenerator = std::make_unique(); + fsVerityGenerator->GenerateFsVerityDigest(inputstream, fileSize, fsvTreeOffset); + std::vector fsVerityDigest = fsVerityGenerator->GetFsVerityDigest(); + std::string ownerID = profileContent.empty() ? "DEBUF_LIB_ID" : HapUtils::GetAppIdentifier(profileContent); + std::vector signature; + bool generateSignatureFlag = GenerateSignature(fsVerityDigest, ownerID, signature); + if (!generateSignatureFlag) { + SIGNATURE_TOOLS_LOGE("[SignElf] generate elf signature failed"); + return false; + } + + FsVerityDescriptor::Builder fsdbuilder; + fsdbuilder.SetFileSize(fileSize) + .SetHashAlgorithm(FS_SHA256.GetId()) + .SetLog2BlockSize(LOG_2_OF_FSVERITY_HASH_PAGE_SIZE) + .SetSaltSize(fsVerityGenerator->GetSaltSize()) + .SetSignSize(signature.size()) + .SetFileSize(fileSize) + .SetSalt(fsVerityGenerator->Getsalt()) + .SetRawRootHash(fsVerityGenerator->GetRootHash()) + .SetFlags(FsVerityDescriptor::FLAG_STORE_MERKLE_TREE_OFFSET) + .SetMerkleTreeOffset(fsvTreeOffset) + .SetCsVersion(FsVerityDescriptor::CODE_SIGN_VERSION); + + FsVerityDescriptorWithSign fsVerityDescriptorWithSign = + FsVerityDescriptorWithSign(FsVerityDescriptor(fsdbuilder), signature); + std::vector treeBytes = fsVerityGenerator->GetTreeBytes(); + ElfSignBlock signBlock = ElfSignBlock(paddingSize, treeBytes, fsVerityDescriptorWithSign); + signBlock.ToByteArray(codesignData); + return true; +} + +bool CodeSigning::SignNativeLibs(std::string input, std::string ownerID) +{ + // 'an' libs are always signed + m_extractedNativeLibSuffixs.push_back(NATIVE_LIB_AN_SUFFIX); + // 'so' libs are always signed + m_extractedNativeLibSuffixs.push_back(NATIVE_LIB_SO_SUFFIX); + // sign native files + std::vector> ret; + UnzipHandleParam param(ret, ownerID, true); + bool nativeLibflag = GetNativeEntriesFromHap(input, param); + if (!nativeLibflag) { + SIGNATURE_TOOLS_LOGE("%s native libs handle failed", input.c_str()); + return false; + } + std::vector> *nativeLibInfoList = param.GetRet(); + if (nativeLibInfoList->empty()) { + SIGNATURE_TOOLS_LOGI("No native libs."); + return true; + } + m_codeSignBlock.GetSoInfoSegment().SetSoInfoList(*nativeLibInfoList); + return true; +} + +void CodeSigning::UpdateCodeSignBlock() +{ + // construct segment header list + m_codeSignBlock.SetSegmentHeaders(); + // Compute and set segment number + m_codeSignBlock.SetSegmentNum(); + // update code sign block header flag + m_codeSignBlock.SetCodeSignBlockFlag(); + // compute segment offset + m_codeSignBlock.ComputeSegmentOffset(); +} + +bool CodeSigning::GetNativeEntriesFromHap(std::string& packageName, UnzipHandleParam& param) +{ + unzFile zFile = unzOpen(packageName.c_str()); + if (zFile == NULL) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "zlib open file: " + packageName + " failed."); + return false; + } + // get zipFile all paramets + unz_global_info zGlobalInfo; + int getRet = unzGetGlobalInfo(zFile, &zGlobalInfo); + if (getRet != UNZ_OK) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "zlib get global info failed."); + unzClose(zFile); + return false; + } + // search each file + bool handleFlag = HandleZipGlobalInfo(zFile, zGlobalInfo, param); + if (!handleFlag) { + unzClose(zFile); + return false; + } + unzCloseCurrentFile(zFile); + unzGoToNextFile(zFile); + unzClose(zFile); + return true; +} + +bool CodeSigning::HandleZipGlobalInfo(unzFile& zFile, unz_global_info& zGlobalInfo, + UnzipHandleParam& param) +{ + char szReadBuffer[BUFFER_SIZE] = { 0 }; + unz_file_info zFileInfo; + char fileName[FILE_NAME_SIZE]; + char fileNameZeroBuf[FILE_NAME_SIZE] = { 0 }; + SIGNATURE_TOOLS_LOGI("zGlobalInfo.number_entry = %lu", zGlobalInfo.number_entry); + for (uLong i = 0; i < zGlobalInfo.number_entry; ++i) { + if (memcpy_s(fileName, FILE_NAME_SIZE, fileNameZeroBuf, FILE_NAME_SIZE) != 0) + return false; + size_t nameLen = 0; + if (!CheckUnzParam(zFile, zFileInfo, fileName, &nameLen)) { + return false; + } + if (!CheckFileName(zFile, fileName, &nameLen)) { + continue; + } + long fileLength = zFileInfo.uncompressed_size; + int readFileSize = 0; + int nReadFileSize; + std::stringbuf sb; + do { + nReadFileSize = 0; + if (memset_s(szReadBuffer, BUFFER_SIZE, 0, BUFFER_SIZE) != EOK) { + SIGNATURE_TOOLS_LOGE("memset_s failed"); + } + nReadFileSize = unzReadCurrentFile(zFile, szReadBuffer, BUFFER_SIZE); + if (nReadFileSize > 0) { + sb.sputn(szReadBuffer, nReadFileSize); + } + fileLength -= nReadFileSize; + readFileSize += nReadFileSize; + } while (fileLength > 0 && nReadFileSize > 0); + if (fileLength) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "zlib read stream from " + + std::string(fileName) + " failed."); + unzCloseCurrentFile(zFile); + unzGoToNextFile(zFile); + return false; + } + bool handleFlag = DoNativeLibSignOrVerify(std::string(fileName), sb, param, readFileSize); + if (!handleFlag) { + SIGNATURE_TOOLS_LOGE("%s native libs handle failed", fileName); + return false; + } + unzCloseCurrentFile(zFile); + unzGoToNextFile(zFile); + } + return true; +} + +bool CodeSigning::DoNativeLibSignOrVerify(std::string fileName, std::stringbuf& sb, + UnzipHandleParam& param, int readFileSize) +{ + std::istream input(&sb); + bool isSign = param.IsSign(); + if (isSign) { + std::string ownerID = param.GetOwnerID(); + std::pair> pairSignInfoAndMerkleTreeBytes; + bool signFileFlag = SignFile(input, readFileSize, false, 0, ownerID, pairSignInfoAndMerkleTreeBytes); + if (!signFileFlag) { + return false; + } + std::vector> *ret = param.GetRet(); + ret->push_back(std::make_pair(fileName, pairSignInfoAndMerkleTreeBytes.first)); + } else { + CodeSignBlock csb = param.GetCodeSignBlock(); + std::vector fileNames = csb.GetSoInfoSegment().GetFileNameList(); + bool isContainFileName = std::find(fileNames.begin(), fileNames.end(), fileName) != fileNames.end(); + if (!isContainFileName) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, + "verify signed file position failed, file: " + fileName); + return false; + } + for (int j = 0; j < csb.GetSoInfoSegment().GetSectionNum(); j++) { + SignInfo signInfo = csb.GetSoInfoSegment().GetSignInfoList()[j]; + std::string entryName = csb.GetSoInfoSegment().GetFileNameList()[j]; + std::vector entrySig = signInfo.GetSignature(); + std::string entrySigStr(entrySig.begin(), entrySig.end()); + if (fileName != entryName) { + continue; + } + if (readFileSize != signInfo.GetDataSize()) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "Invalid dataSize of native lib"); + return false; + } + bool verifyFlag = VerifyCodeSignature::VerifySingleFile(input, readFileSize, entrySig, 0, + std::vector()); + if (!verifyFlag) { + return false; + } + std::ifstream* inputFile = (std::ifstream*)(&input); + inputFile->close(); + std::pair pairResult = param.GetPairResult(); + bool checkOwnerIDFlag = CmsUtils::CheckOwnerID(entrySigStr, pairResult.first, pairResult.second); + if (!checkOwnerIDFlag) { + return false; + } + } + } + return true; +} + +bool CodeSigning::CheckUnzParam(unzFile& zFile, unz_file_info& zFileInfo, + char fileName[], size_t* nameLen) +{ + if (UNZ_OK != unzGetCurrentFileInfo(zFile, &zFileInfo, fileName, + FILE_NAME_SIZE, NULL, 0, NULL, 0)) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "unzip get file: " + std::string(fileName) + "info failed!"); + return false; + } + SIGNATURE_TOOLS_LOGI("Open zipFile filename is : %s", fileName); + if ((*nameLen = strlen(fileName)) == 0U) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "Open zipFile fileName is null"); + return false; + } + if (UNZ_OK != unzOpenCurrentFile(zFile)) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "unzOpenCurrentFile zipFile error"); + return false; + } + return true; +} + +bool CodeSigning::CheckFileName(unzFile& zFile, char fileName[], size_t* nameLen) +{ + if (fileName[*nameLen - 1] == '/') { + SIGNATURE_TOOLS_LOGI("It is dictionary."); + unzCloseCurrentFile(zFile); + unzGoToNextFile(zFile); + return false; + } + std::string str(fileName); + bool nativeFileFlag = IsNativeFile(str); + if (!nativeFileFlag) { + SIGNATURE_TOOLS_LOGI("Suffix mismatched."); + unzCloseCurrentFile(zFile); + unzGoToNextFile(zFile); + return false; + } + return true; +} + +bool CodeSigning::IsNativeFile(std::string& input) +{ + size_t dotPos = input.rfind('.'); + if (dotPos == std::string::npos) { + return false; + } + std::string suffix = input.substr(dotPos + 1); + if (suffix == "an") { + return true; + } + std::string libDir = input.substr(0, LIBS_PATH_PREFIX.size()); + int ret = LIBS_PATH_PREFIX.compare(libDir); + if (ret == 0) { + return true; + } + return false; +} + +bool CodeSigning::GenerateSignature(std::vector& signedData, const std::string& ownerID, + std::vector& ret) +{ + if (m_signConfig->GetSigner() != nullptr) { + STACK_OF(X509)* certs = NULL; + certs = m_signConfig->GetSigner()->GetCertificates(); + if (certs == nullptr) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "No certificates configured for sign."); + return false; + } + sk_X509_pop_free(certs, X509_free); + } else { + return false; + } + std::unique_ptr bcSignedDataGenerator = + std::make_unique(); + if (!ownerID.empty()) { + SIGNATURE_TOOLS_LOGW("generate signature get owner id not null."); + bcSignedDataGenerator->SetOwnerId(ownerID); + } + std::string signed_data(signedData.begin(), signedData.end()); + std::string ret_str; + if (signedData.empty()) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "Generate verity digest is null"); + return false; + } + bool generateSignedDataFlag = bcSignedDataGenerator->GenerateSignedData(signed_data, m_signConfig, ret_str); + if (generateSignedDataFlag) { + SIGNATURE_TOOLS_LOGE("Generate signedData failed"); + return false; + } + ret = std::vector(ret_str.begin(), ret_str.end()); + return true; +} +} // namespace SignatureTools +} // namespace OHOS diff --git a/hapsigntool_cpp/codesigning/sign/src/verify_code_signature.cpp b/hapsigntool_cpp/codesigning/sign/src/verify_code_signature.cpp new file mode 100644 index 0000000000000000000000000000000000000000..76719c3e54b6730d2460c8e0e67c3d316f739672 --- /dev/null +++ b/hapsigntool_cpp/codesigning/sign/src/verify_code_signature.cpp @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2024-2024 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_code_signature.h" +#include "elf_sign_block.h" +#include "constant.h" + +namespace OHOS { +namespace SignatureTools { +bool VerifyCodeSignature::VerifyHap(std::string file, int64_t offset, int64_t length, + std::string fileFormat, std::string profileContent) +{ + if (std::find(CodeSigning::SUPPORT_FILE_FORM.begin(), CodeSigning::SUPPORT_FILE_FORM.end(), + fileFormat) == CodeSigning::SUPPORT_FILE_FORM.end()) { + SIGNATURE_TOOLS_LOGI("Not hap, hsp or hqf file, skip code signing verify, file type: %s", fileFormat.c_str()); + return true; + } + // 1) generate CodeSignBlock + std::pair pairResult = HapUtils::ParseAppIdentifier(profileContent); + CodeSignBlock csb; + bool generateFlag = GenerateCodeSignBlock(file, offset, length, csb); + if (!generateFlag) { + SIGNATURE_TOOLS_LOGE("VerifyHap GenerateCodeSignBlock failed, file: %s", file.c_str()); + return false; + } + // 2) verify hap + bool verifyFlag = VerifyCodeSign(file, pairResult, csb); + if (!verifyFlag) { + SIGNATURE_TOOLS_LOGE("VerifyHap VerifyCodeSign failed"); + return false; + } + return true; +} + +bool VerifyCodeSignature::VerifyElf(std::string file, int64_t offset, int64_t length, + std::string fileFormat, std::string profileContent) +{ + std::transform(fileFormat.begin(), fileFormat.end(), fileFormat.begin(), ::tolower); + if (ELF != fileFormat) { + SIGNATURE_TOOLS_LOGI("Not elf file, skip code signing verify, file type: %s", fileFormat.c_str()); + return true; + } + // 1) parse sign block to ElfSignBlock object + std::ifstream signedElf(file, std::ios::binary); + if (!signedElf.is_open()) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open file: " + file + "failed"); + return false; + } + signedElf.seekg(offset, std::ios::beg); + std::vector codeSignBlockBytes(length); + signedElf.read(codeSignBlockBytes.data(), codeSignBlockBytes.size()); + signedElf.close(); + ElfSignBlock elfSignBlock; + bool arrFlag = ElfSignBlock::FromByteArray(*(std::vector *) & codeSignBlockBytes, elfSignBlock); + if (!arrFlag) { + SIGNATURE_TOOLS_LOGE("parse sign block to ElfCodeSignBlock object failed"); + return false; + } + // 2) verify file data + int32_t paddingSize = ElfSignBlock::ComputeMerkleTreePaddingLength(offset); + std::vector &merkleTreeWithPadding = elfSignBlock.GetMerkleTreeWithPadding(); + std::vector merkleTree; + merkleTree.insert(merkleTree.end(), merkleTreeWithPadding.begin() + paddingSize, merkleTreeWithPadding.end()); + std::ifstream elf(file, std::ios::binary); + bool verifySingleFileFlag = VerifySingleFile(elf, elfSignBlock.GetDataSize(), elfSignBlock.GetSignature(), + elfSignBlock.GetTreeOffset(), merkleTree); + if (!verifySingleFileFlag) { + SIGNATURE_TOOLS_LOGE("verify elf file data failed"); + elf.close(); + return false; + } + elf.close(); + // 3) check ownerID + if (!profileContent.empty()) { + std::pair pairResult = HapUtils::ParseAppIdentifier(profileContent); + std::vector signature = elfSignBlock.GetSignature(); + std::string signatureStr(signature.begin(), signature.end()); + bool checkOwnerIDFlag = CmsUtils::CheckOwnerID(signatureStr, pairResult.first, pairResult.second); + if (!checkOwnerIDFlag) { + SIGNATURE_TOOLS_LOGE("elf check owner id failed"); + return false; + } + } + return true; +} + +bool VerifyCodeSignature::VerifyNativeLib(CodeSignBlock& csb, std::string& file, unzFile& zFile, + std::pair& pairResult) +{ + UnzipHandleParam param(csb, pairResult, false); + CodeSigning codeSigning; + bool nativeFlag = codeSigning.GetNativeEntriesFromHap(file, param); + if (!nativeFlag) { + SIGNATURE_TOOLS_LOGE("verify native libs failed, file: %s", file.c_str()); + return false; + } + return true; +} + +bool VerifyCodeSignature::VerifyCodeSign(std::string file, std::pair& pairResult, + CodeSignBlock& csb) +{ + // 1) verify hap + std::ifstream hap(file, std::ios::binary); + if (!hap.is_open()) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open file: " + file + "failed"); + return false; + } + int64_t dataSize = csb.GetHapInfoSegment().GetSignInfo().GetDataSize(); + std::vector signature = csb.GetHapInfoSegment().GetSignInfo().GetSignature(); + Extension* ext = csb.GetHapInfoSegment().GetSignInfo() + .GetExtensionByType(MerkleTreeExtension::MERKLE_TREE_INLINED); + MerkleTreeExtension* mte = new MerkleTreeExtension(0, 0, std::vector()); + if (ext != nullptr) { + delete mte; + mte = (MerkleTreeExtension*)(ext); + } else { + std::shared_ptr merkleTreeExt(mte); + } + // temporary: merkle tree offset set to zero, change to merkleTreeOffset + bool verifyFlag = VerifySingleFile(hap, dataSize, signature, mte->GetMerkleTreeOffset(), + csb.GetOneMerkleTreeByFileName(CodeSigning::HAP_SIGNATURE_ENTRY_NAME)); + if (!verifyFlag) { + return false; + } + hap.close(); + std::string signature_(signature.begin(), signature.end()); + bool checkOwnerIDFlag = CmsUtils::CheckOwnerID(signature_, pairResult.first, pairResult.second); + if (!checkOwnerIDFlag) { + return false; + } + // 2) verify native libs + unzFile zFile = unzOpen(file.c_str()); + if (zFile == NULL) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "unzOpen file: " + file + "failed"); + return false; + } + bool verifyNativeLibFlag = VerifyNativeLib(csb, file, zFile, pairResult); + if (!verifyNativeLibFlag) { + return false; + } + unzClose(zFile); + return true; +} + +bool VerifyCodeSignature::VerifySingleFile(std::istream& input, int64_t length, + std::vector signature, + int64_t merkleTreeOffset, + std::vector inMerkleTreeBytes) +{ + std::pair, std::vector> pairResult + = GenerateFsVerityDigest(input, length, merkleTreeOffset); + std::vector generatedMerkleTreeBytes = pairResult.second; + // For native libs, inMerkleTreeBytes is null, skip check here + bool verifyFlag = (!inMerkleTreeBytes.empty()) && !AreVectorsEqual(inMerkleTreeBytes, generatedMerkleTreeBytes); + if (verifyFlag) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "verify merkle tree bytes failed"); + return false; + } + return CmsUtils::VerifySignDataWithUnsignedDataDigest(pairResult.first, signature); +} + +bool VerifyCodeSignature::GenerateCodeSignBlock(const std::string& file, int64_t offset, + int64_t length, CodeSignBlock& csb) +{ + // 1) parse sign block to CodeSignBlock object + std::ifstream signedHap(file, std::ios::binary); + if (!signedHap.is_open()) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open file: " + file + "failed"); + return false; + } + int32_t fileReadOffset = 0; + // 1.1) skip data part, but fileReadOffset remains at start(0) + signedHap.seekg(offset, std::ios::beg); + // 1.2) parse codeSignBlockHeader + std::vector codeSignBlockHeaderByteArray(CodeSignBlockHeader::Size()); + signedHap.read(codeSignBlockHeaderByteArray.data(), codeSignBlockHeaderByteArray.size()); + fileReadOffset += signedHap.gcount(); + CodeSignBlockHeader* pCodeSignBlockHeader = + CodeSignBlockHeader::FromByteArray(*(std::vector*) &codeSignBlockHeaderByteArray); + if (nullptr == pCodeSignBlockHeader) { + SIGNATURE_TOOLS_LOGE("Invalid code Sign block header"); + signedHap.close(); + return false; + } + std::shared_ptr codeSignBlockHeader(pCodeSignBlockHeader); + csb.SetCodeSignBlockHeader(*codeSignBlockHeader); + int64_t headerBlockSize = csb.GetCodeSignBlockHeader().GetBlockSize(); + if (headerBlockSize != length) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, + "Invalid code Sign block size of setCodeSignBlockHeader"); + signedHap.close(); + return false; + } + // 2) parse segment headers + for (int i = 0; i < csb.GetCodeSignBlockHeader().GetSegmentNum(); i++) { + std::vector segmentHeaderByteArray(SegmentHeader::SEGMENT_HEADER_LENGTH); + signedHap.read(segmentHeaderByteArray.data(), segmentHeaderByteArray.size()); + fileReadOffset += signedHap.gcount(); + csb.AddToSegmentList(*SegmentHeader::FromByteArray(*(std::vector *) &segmentHeaderByteArray)); + } + // compute merkle tree offset by alignment, based on file start + int64_t computedTreeOffset = GetAlignmentAddr(CodeSignBlock::PAGE_SIZE_4K, fileReadOffset + offset); + // skip zero padding before merkle tree, adds zero padding length to fileReadOffset + signedHap.seekg(computedTreeOffset - offset - fileReadOffset, std::ios::cur); + fileReadOffset += computedTreeOffset - offset - fileReadOffset; + bool parseMerkleTreeFlag = ParseMerkleTree(csb, fileReadOffset, signedHap, computedTreeOffset); + if (!parseMerkleTreeFlag) { + SIGNATURE_TOOLS_LOGE("GenerateCodeSignBlock parse merkle tree failed."); + return false; + } + signedHap.close(); + return true; +} + +bool VerifyCodeSignature::ParseSegmentHead(CodeSignBlock& csb, std::ifstream& signedHap, + std::vector &merkleTreeBytes, int32_t &fileReadOffset) +{ + for (auto& segmentHeader : csb.GetSegmentHeaderList()) { + if (fileReadOffset > segmentHeader.GetSegmentOffset()) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "Invaild offset of merkle tree and segment header"); + return false; + } + // get merkle tree bytes + if (fileReadOffset < segmentHeader.GetSegmentOffset()) { + merkleTreeBytes.resize(segmentHeader.GetSegmentOffset() - fileReadOffset); + signedHap.read(merkleTreeBytes.data(), merkleTreeBytes.size()); + fileReadOffset += signedHap.gcount(); + } + std::vector sh(segmentHeader.GetSegmentSize(), 0); + signedHap.read(sh.data(), sh.size()); + fileReadOffset += signedHap.gcount(); + int32_t type = segmentHeader.GetType(); + if (type == SegmentHeader::CSB_FSVERITY_INFO_SEG) { + // 3) parse fs-verity info segment + FsVerityInfoSegment fsVerityInfoSegment = + FsVerityInfoSegment::FromByteArray(*(std::vector *) & sh); + csb.SetFsVerityInfoSegment(fsVerityInfoSegment); + } else if (type == SegmentHeader::CSB_HAP_META_SEG) { + // 4) parse hap info segment + HapInfoSegment hapInfoSegment = HapInfoSegment::FromByteArray(*(std::vector *) & sh); + csb.SetHapInfoSegment(hapInfoSegment); + } else if (type == SegmentHeader::CSB_NATIVE_LIB_INFO_SEG) { + // 5) parse so info segment + NativeLibInfoSegment nativeLibInfoSegment = + NativeLibInfoSegment::FromByteArray(*(std::vector *) & sh); + csb.SetSoInfoSegment(nativeLibInfoSegment); + } + } + + return true; +} + +bool VerifyCodeSignature::ParseMerkleTree(CodeSignBlock& csb, int32_t readOffset, std::ifstream& signedHap, + int64_t computedTreeOffset) +{ + std::vector merkleTreeBytes; + int32_t fileReadOffset = readOffset; + bool parseFlag = ParseSegmentHead(csb, signedHap, merkleTreeBytes, fileReadOffset); + if (!parseFlag) { + SIGNATURE_TOOLS_LOGE("ParsesegmentHead failed"); + return false; + } + int32_t blockSize = csb.GetCodeSignBlockHeader().GetBlockSize(); + if (fileReadOffset != blockSize) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, + "Invalid blockSize of getCodeSignBlockHeader"); + return false; + } + // parse merkle tree + Extension* extension = csb.GetHapInfoSegment().GetSignInfo(). + GetExtensionByType(MerkleTreeExtension::MERKLE_TREE_INLINED); + if (!extension) { + SIGNATURE_TOOLS_LOGE("Missing merkleTreeExtension in verifycation"); + return false; + } + MerkleTreeExtension* mte = (MerkleTreeExtension*)(extension); + if (mte) { + bool merkleTreeFlag = computedTreeOffset != mte->GetMerkleTreeOffset() || + merkleTreeBytes.size() != mte->GetMerkleTreeSize(); + if (merkleTreeFlag) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "Invalid merkle tree offset or tree size"); + return false; + } + csb.AddOneMerkleTree(CodeSigning::HAP_SIGNATURE_ENTRY_NAME, *(std::vector *) &merkleTreeBytes); + } + return true; +} + +int64_t VerifyCodeSignature::GetAlignmentAddr(int64_t alignment, int64_t input) +{ + if (alignment == 0) { + return input; + } + int64_t residual = input % alignment; + if (residual == 0) { + return input; + } else { + return input + (alignment - residual); + } +} + +std::pair, std::vector> VerifyCodeSignature::GenerateFsVerityDigest( + std::istream& inputStream, int64_t size, int64_t merkleTreeOffset) +{ + std::unique_ptr fsVerityGenerator = std::make_unique(); + fsVerityGenerator->GenerateFsVerityDigest(inputStream, size, merkleTreeOffset); + return std::make_pair(fsVerityGenerator->GetFsVerityDigest(), fsVerityGenerator->GetTreeBytes()); +} + +bool VerifyCodeSignature::AreVectorsEqual(const std::vector& vec1, const std::vector& vec2) +{ + if (vec1.size() != vec2.size()) { + return false; + } + for (int64_t i = 0; i < vec1.size(); i++) { + if (vec1[i] != vec2[i]) { + return false; + } + } + return true; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/signature_tools_codesigning.gni b/hapsigntool_cpp/codesigning/signature_tools_codesigning.gni new file mode 100644 index 0000000000000000000000000000000000000000..38ddec02b552a860731c0f6940c5115427363166 --- /dev/null +++ b/hapsigntool_cpp/codesigning/signature_tools_codesigning.gni @@ -0,0 +1,46 @@ +# Copyright (c) 2024 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_codesigning_include = [ + "${signature_tools_codesigning}/datastructure/include", + "${signature_tools_codesigning}/fsverity/include", + "${signature_tools_codesigning}/utils/include", + "${signature_tools_codesigning}/sign/include", +] + +signature_tools_codesigning_src = [ + "${signature_tools_codesigning}/datastructure/src/code_sign_block.cpp", + "${signature_tools_codesigning}/datastructure/src/code_sign_block_header.cpp", + "${signature_tools_codesigning}/datastructure/src/extension.cpp", + "${signature_tools_codesigning}/datastructure/src/fs_verity_info_segment.cpp", + "${signature_tools_codesigning}/datastructure/src/hap_info_segment.cpp", + "${signature_tools_codesigning}/datastructure/src/merkle_tree_extension.cpp", + "${signature_tools_codesigning}/datastructure/src/native_lib_info_segment.cpp", + "${signature_tools_codesigning}/datastructure/src/segment_header.cpp", + "${signature_tools_codesigning}/datastructure/src/sign_info.cpp", + "${signature_tools_codesigning}/datastructure/src/signed_file_pos.cpp", + "${signature_tools_codesigning}/datastructure/src/elf_sign_block.cpp", + "${signature_tools_codesigning}/datastructure/src/unzip_handle_param.cpp", + "${signature_tools_codesigning}/fsverity/src/fs_verity_descriptor.cpp", + "${signature_tools_codesigning}/fsverity/src/fs_verity_digest.cpp", + "${signature_tools_codesigning}/fsverity/src/fs_verity_generator.cpp", + "${signature_tools_codesigning}/fsverity/src/fs_verity_hash_algorithm.cpp", + "${signature_tools_codesigning}/fsverity/src/merkle_tree_builder.cpp", + "${signature_tools_codesigning}/fsverity/src/fs_verity_descriptor_with_sign.cpp", + "${signature_tools_codesigning}/utils/src/fs_digest_utils.cpp", + "${signature_tools_codesigning}/utils/src/cms_utils.cpp", + "${signature_tools_codesigning}/sign/src/bc_signeddata_generator.cpp", + "${signature_tools_codesigning}/sign/src/code_signing.cpp", + "${signature_tools_codesigning}/sign/src/verify_code_signature.cpp", +] diff --git a/hapsigntool_cpp/codesigning/utils/include/cms_utils.h b/hapsigntool_cpp/codesigning/utils/include/cms_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..1574b141f96899254aa7f898718fcf606d7fa5cc --- /dev/null +++ b/hapsigntool_cpp/codesigning/utils/include/cms_utils.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024-2024 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_CMS_UTILS_H +#define SIGNATURETOOLS_CMS_UTILS_H + +#include +#include +#include + +#include "signature_tools_log.h" +#include "pkcs7_data.h" + +namespace OHOS { +namespace SignatureTools { +class CmsUtils { +public: + static bool VerifySignDataWithUnsignedDataDigest(const std::vector& unsignedDataDigest, + const std::vector& signedData); + static bool CheckOwnerID(const std::string& signature, const std::string& profileOwnerID, + const std::string& profileType); + static int CreateNIDFromOID(const std::string& oid, const std::string& shortName, + const std::string& longName); +private: + CmsUtils(); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATURETOOLS_CMS_UTILS_H \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/utils/include/fs_digest_utils.h b/hapsigntool_cpp/codesigning/utils/include/fs_digest_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..89b70c96d54977ca751ac8151c17a24f6b89d11c --- /dev/null +++ b/hapsigntool_cpp/codesigning/utils/include/fs_digest_utils.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024-2024 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_FS_DIGEST_UTILS_H +#define SIGNATURETOOLS_FS_DIGEST_UTILS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "signature_tools_log.h" + +using hashFunc = const EVP_MD* (*)(void); + +enum HashType { + HASH_SHA256, + HASH_SHA384 +}; + +class DigestUtils { +public: + enum class Type :char { + BINARY, HEX + }; + explicit DigestUtils(HashType type); + ~DigestUtils(); + void AddData(std::string data); + void AddData(const char* data, int length); + std::string Result(Type type = Type::HEX); + +private: + EVP_MD_CTX* m_ctx = NULL; + HashType m_type; +}; +#endif // SIGNATURETOOLS_FS_DIGEST_UTILS_H diff --git a/hapsigntool_cpp/codesigning/utils/src/cms_utils.cpp b/hapsigntool_cpp/codesigning/utils/src/cms_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e1a5ed6e55869063f97ad228186f71fe6162764c --- /dev/null +++ b/hapsigntool_cpp/codesigning/utils/src/cms_utils.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2024-2024 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 "cms_utils.h" +#include "bc_signeddata_generator.h" +#include "constant.h" + +namespace OHOS { +namespace SignatureTools { + +bool CmsUtils::VerifySignDataWithUnsignedDataDigest(const std::vector& unsignedDataDigest, + const std::vector& signedData) +{ + int ret = 0; + std::string unsignedDataDigest_(unsignedDataDigest.begin(), unsignedDataDigest.end()); + PKCS7Data p7Data(PKCS7_DETACHED_FLAGS); + ret = p7Data.Parse(signedData); + if (ret < 0) { + SIGNATURE_TOOLS_LOGE("verify pkcs7 signed data block bytes failed"); + return false; + } + ret = p7Data.Verify(unsignedDataDigest_); + if (ret < 0) { + SIGNATURE_TOOLS_LOGE("verify pkcs7 signed datablock failed"); + return false; + } + return true; +} + +bool CmsUtils::CheckOwnerID(const std::string& signature, const std::string& profileOwnerID, + const std::string& profileType) +{ + std::string ownerID = profileOwnerID; + if (DEBUG_STR == profileType) ownerID = DEBUG_LIB_ID; + int nid = CreateNIDFromOID(OWNERID_OID, OWNERID_OID_SHORT_NAME, OWNERID_OID_LONG_NAME); + const unsigned char* data = reinterpret_cast(signature.c_str()); + PKCS7* p7 = d2i_PKCS7(NULL, &data, static_cast(signature.size())); + if (p7 == nullptr) { + PrintErrorNumberMsg("PARSE_ERROR", PARSE_ERROR, "invalid data, parse pkcs7 failed"); + return false; + } + STACK_OF(PKCS7_SIGNER_INFO)* signerInfosk = PKCS7_get_signer_info(p7); + if (signerInfosk == nullptr) { + PKCS7_free(p7); + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, "can't get signerinfo from pkcs7"); + return true; + } + for (int i = 0; i < sk_PKCS7_SIGNER_INFO_num(signerInfosk); i++) { + PKCS7_SIGNER_INFO* signerInfo = sk_PKCS7_SIGNER_INFO_value(signerInfosk, i); + ASN1_TYPE* asn1Type = PKCS7_get_signed_attribute(signerInfo, nid); + if (asn1Type == nullptr) { + if (DEBUG_STR == profileType) + continue; + if (ownerID.empty()) { + continue; + } else { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "app-identifier is not in the signature"); + PKCS7_free(p7); + return false; + } + } + if (ownerID.empty()) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "app-identifier in profile is null,in signature exist"); + PKCS7_free(p7); + return false; + } + if (asn1Type->type == V_ASN1_UTF8STRING) { + ASN1_STRING* result = asn1Type->value.asn1_string; + std::string result_ownerID; + result_ownerID.assign(reinterpret_cast(ASN1_STRING_get0_data(result)), + ASN1_STRING_length(result)); + if (ownerID != result_ownerID) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "app-identifier in signature is invalid"); + PKCS7_free(p7); + return false; + } + } + } + PKCS7_free(p7); + return true; +} + +int CmsUtils::CreateNIDFromOID(const std::string& oid, const std::string& shortName, + const std::string& longName) +{ + int nid = OBJ_txt2nid(oid.c_str()); + if (nid == NID_undef) { + nid = OBJ_create(oid.c_str(), shortName.c_str(), longName.c_str()); + } + return nid; +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/codesigning/utils/src/fs_digest_utils.cpp b/hapsigntool_cpp/codesigning/utils/src/fs_digest_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..36e5c331fa9a85c2b43ec8c3209338b1713aaa15 --- /dev/null +++ b/hapsigntool_cpp/codesigning/utils/src/fs_digest_utils.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024-2024 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 "fs_digest_utils.h" +#include "securec.h" + +void DigestUtils::AddData(std::string data) +{ + AddData(data.data(), (int)data.size()); +} + +void DigestUtils::AddData(const char* data, int length) +{ + int ret = EVP_DigestUpdate(m_ctx, data, length); + if (ret < 1) { + printf("Update DigestFunc failed!\n"); + } +} + +std::string DigestUtils::Result(DigestUtils::Type type) +{ + unsigned int len = 0; + + const std::map hashLength = { + {HASH_SHA256, SHA256_DIGEST_LENGTH}, + {HASH_SHA384, SHA384_DIGEST_LENGTH}, + }; + + unsigned char* md = reinterpret_cast(new char[hashLength.at(m_type)]); + int ret = EVP_DigestFinal_ex(m_ctx, md, &len); + if (ret < 1) { + printf("Failed to Calculate Hash Relsult\n"); + } + int temporaryVariableFirst = 2; + int temporaryVariableSecond = 3; + if (type == Type::HEX) { + char* res = new char[len * temporaryVariableFirst + 1]; + for (unsigned int i = 0; i < len; i++) { + snprintf_s(&res[i * temporaryVariableFirst], temporaryVariableSecond, + temporaryVariableFirst, "%02x", md[i]); + } + std::string st{res, len * temporaryVariableFirst}; + delete[]md; + delete[]res; + return st; + } + std::string st{reinterpret_cast(md), len}; + delete[]md; + return st; +} + +DigestUtils::DigestUtils(HashType type) +{ + m_type = type; + m_ctx = EVP_MD_CTX_new(); + + const std::map hashMethods = { + {HASH_SHA256, EVP_sha256}, + {HASH_SHA384, EVP_sha384} + }; + + int ret = EVP_DigestInit_ex(m_ctx, hashMethods.at(type)(), nullptr); + if (ret < 1) { + printf("Init DigestFunc failed!\n"); + } +} + +DigestUtils::~DigestUtils() +{ + if (m_ctx != nullptr) { + EVP_MD_CTX_free(m_ctx); + } +} \ No newline at end of file diff --git a/hapsigntool_cpp/common/include/byte_buffer.h b/hapsigntool_cpp/common/include/byte_buffer.h new file mode 100644 index 0000000000000000000000000000000000000000..d32ae4e0ee34672de40d130a4c45021cfa2667b3 --- /dev/null +++ b/hapsigntool_cpp/common/include/byte_buffer.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2024-2024 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 GetUInt64(uint64_t& value); + DLL_EXPORT bool GetUInt64(int32_t index, uint64_t& value); + 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 PutUInt64(uint64_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 std::string GetData(int32_t len); + 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/hapsigntool_cpp/common/include/byte_buffer_data_source.h b/hapsigntool_cpp/common/include/byte_buffer_data_source.h new file mode 100644 index 0000000000000000000000000000000000000000..eb93d5d88125da20ba5efa0aa60a0a814c55f46a --- /dev/null +++ b/hapsigntool_cpp/common/include/byte_buffer_data_source.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024-2024 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_DATASOURCE_H +#define SIGNATRUETOOLS_BYTEBUFFER_DATASOURCE_H + +#include "data_source.h" +#include "export_define.h" +#include "byte_buffer.h" +#include "digest_parameter.h" + +namespace OHOS { +namespace SignatureTools { + +class ByteBufferDataSource : public DataSource { +public: + DLL_EXPORT ByteBufferDataSource(ByteBuffer& hapBuffer); + DLL_EXPORT ~ByteBufferDataSource(); + bool HasRemaining() const override; + int64_t Remaining() const override; + void Reset() override; + bool ReadDataAndDigestUpdate(const DigestParameter& digestParam, int32_t chunkSize) override; + ByteBuffer& GetByteBuffer() + { + return bytebuffer; + } + +private: + ByteBuffer& bytebuffer; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_BYTEBUFFER_DATASOURCE_H diff --git a/hapsigntool_cpp/common/include/constant.h b/hapsigntool_cpp/common/include/constant.h new file mode 100644 index 0000000000000000000000000000000000000000..dbd3ad5c3f90092e6f426edd0ba571651ad33842 --- /dev/null +++ b/hapsigntool_cpp/common/include/constant.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2024-2024 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_APP = "sign-app"; +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/hapsigntool_cpp/common/include/data_source.h b/hapsigntool_cpp/common/include/data_source.h new file mode 100644 index 0000000000000000000000000000000000000000..77ac1e21f9435e5dfc4983895d015a2504f18703 --- /dev/null +++ b/hapsigntool_cpp/common/include/data_source.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024-2024 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_DATASOURCE_H +#define SIGNATRUETOOLS_DATASOURCE_H + +#include "byte_buffer.h" +#include "verify_hap_openssl_utils.h" + +namespace OHOS { +namespace SignatureTools { + +class DataSource { +public: + virtual bool HasRemaining() const = 0; + virtual int64_t Remaining() const = 0; + virtual void Reset() = 0; + virtual bool ReadDataAndDigestUpdate(const DigestParameter& digestParam, int32_t chunkSize) = 0; + + virtual ~DataSource() + { + } +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_DATASOURCE_H diff --git a/hapsigntool_cpp/common/include/digest_parameter.h b/hapsigntool_cpp/common/include/digest_parameter.h new file mode 100644 index 0000000000000000000000000000000000000000..09891b370ec720866a5de859b661237fa681d9b4 --- /dev/null +++ b/hapsigntool_cpp/common/include/digest_parameter.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024-2024 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* ptrCtx; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_DIGESTPARAMETER_H diff --git a/hapsigntool_cpp/common/include/export_define.h b/hapsigntool_cpp/common/include/export_define.h new file mode 100644 index 0000000000000000000000000000000000000000..5db074e982044937ad4b41905139270f9fd82e22 --- /dev/null +++ b/hapsigntool_cpp/common/include/export_define.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024-2024 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/hapsigntool_cpp/common/include/file_data_source.h b/hapsigntool_cpp/common/include/file_data_source.h new file mode 100644 index 0000000000000000000000000000000000000000..2212cc0e0fec154c09a19123a993cc5f4a06b0da --- /dev/null +++ b/hapsigntool_cpp/common/include/file_data_source.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024-2024 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_HAPFILEDATASOURCE_H +#define SIGNATRUETOOLS_HAPFILEDATASOURCE_H + +#include "data_source.h" +#include "random_access_file.h" +#include "digest_parameter.h" + +namespace OHOS { +namespace SignatureTools { + +class FileDataSource : public DataSource { +public: + FileDataSource(RandomAccessFile& hapFile, int64_t offset, int64_t size, int64_t position); + ~FileDataSource(); + bool HasRemaining() const override; + int64_t Remaining() const override; + void Reset() override; + bool ReadDataAndDigestUpdate(const DigestParameter& digestParam, int32_t chunkSize) override; + +private: + RandomAccessFile& hapFileRandomAccess; + int64_t fileOffset; + int64_t sourceSize; + int64_t sourcePosition; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_HAPFILEDATASOURCE_H diff --git a/hapsigntool_cpp/common/include/pkcs7_context.h b/hapsigntool_cpp/common/include/pkcs7_context.h new file mode 100644 index 0000000000000000000000000000000000000000..5738ca3e63ee8e52e8d441ba84af0f3fa912042b --- /dev/null +++ b/hapsigntool_cpp/common/include/pkcs7_context.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024-2024 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 certChains; + ByteBuffer content; + Pkcs7Context() + : needWriteCrl(false), digestAlgorithm(0), matchResult(), certIssuer(), + p7(nullptr), certChains(), content() + { + } + ~Pkcs7Context() + { + if (p7 != nullptr) { + PKCS7_free(p7); + p7 = nullptr; + } + for (auto certChain : certChains) { + for (auto cert : certChain) { + X509_free(cert); + } + } + certChains.clear(); + } +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_PKCS7_CONTEXT_H diff --git a/hapsigntool_cpp/common/include/random_access_file.h b/hapsigntool_cpp/common/include/random_access_file.h new file mode 100644 index 0000000000000000000000000000000000000000..d4f8dd4d2fbaf8bc32911de0058c453927c07761 --- /dev/null +++ b/hapsigntool_cpp/common/include/random_access_file.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024-2024 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_RANDOM_ACCESS_FILE_H +#define SIGNATRUETOOLS_RANDOM_ACCESS_FILE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "export_define.h" +#include "byte_buffer.h" +#include "digest_parameter.h" + +namespace OHOS { +namespace SignatureTools { + +struct MmapInfo { + int64_t mmapPosition; + int32_t readMoreLen = 0; + int32_t mmapSize = 0; + char* mapAddr; +}; + +class RandomAccessFile { +public: + DLL_EXPORT RandomAccessFile(); + DLL_EXPORT ~RandomAccessFile(); + DLL_EXPORT bool Init(const std::string& filePath); + DLL_EXPORT int64_t GetLength() const; + DLL_EXPORT int32_t ReadFileFullyFromOffset(ByteBuffer& buffer, int64_t offset); + DLL_EXPORT int32_t ReadFileFullyFromOffset(char buf[], int64_t offset, int64_t bufCapacity); + DLL_EXPORT int32_t WriteToFile(ByteBuffer& buffer, int64_t position, int64_t length); + DLL_EXPORT bool ReadFileFromOffsetAndDigestUpdate(const DigestParameter& digestParam, int32_t chunkSize, + int64_t offset); + +private: + int32_t DoMMap(int32_t bufCapacity, int64_t offset, MmapInfo& mmapInfo); + bool CheckLittleEndian(); + static int32_t memoryPageSize; + int32_t fd = 0; + int64_t fileLength; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_RANDOM_ACCESS_FILE_H diff --git a/hapsigntool_cpp/common/signature_tools_common.gni b/hapsigntool_cpp/common/signature_tools_common.gni new file mode 100644 index 0000000000000000000000000000000000000000..ceeec2a62502ecfe090354638b7f2b6ee59b1716 --- /dev/null +++ b/hapsigntool_cpp/common/signature_tools_common.gni @@ -0,0 +1,23 @@ +# Copyright (c) 2024 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_data_source.cpp", + "${signature_tools_common}/src/byte_buffer.cpp", + "${signature_tools_common}/src/file_data_source.cpp", + "${signature_tools_common}/src/random_access_file.cpp", + "${signature_tools_common}/src/digest_parameter.cpp", +] diff --git a/hapsigntool_cpp/common/src/byte_buffer.cpp b/hapsigntool_cpp/common/src/byte_buffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5f7dabf52142b7bad34014813bb42c0579c8e91d --- /dev/null +++ b/hapsigntool_cpp/common/src/byte_buffer.cpp @@ -0,0 +1,675 @@ +/* + * Copyright (c) 2024-2024 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; + +template +std::shared_ptr make_shared_array(size_t size) +{ + if (size <= 0) + 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::GetUInt64(uint64_t& value) +{ + if (!GetUInt64(0, value)) { + SIGNATURE_TOOLS_LOGE("GetUInt64 failed"); + return false; + } + position += sizeof(uint64_t); + return true; +} + +bool ByteBuffer::GetUInt64(int32_t index, uint64_t& value) +{ + if (!CheckInputForGettingData(index, sizeof(uint64_t))) { + SIGNATURE_TOOLS_LOGE("Failed to get UInt64"); + return false; + } + if (memcpy_s(&value, sizeof(value), (buffer.get() + position + index), sizeof(uint64_t)) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + 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::PutUInt64(uint64_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; + } +} + +std::string ByteBuffer::GetData(int32_t len) +{ + std::unique_ptr pData = std::make_unique(len); + if (0 == memcpy_s(pData.get(), len, buffer.get() + position, len)) { + position = position + len; + } + return std::string(pData.get()); +} + +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 (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/hapsigntool_cpp/common/src/byte_buffer_data_source.cpp b/hapsigntool_cpp/common/src/byte_buffer_data_source.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fb9a49c4531304da653aefc7089921848a98ba69 --- /dev/null +++ b/hapsigntool_cpp/common/src/byte_buffer_data_source.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024-2024 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_data_source.h" +#include "verify_hap_openssl_utils.h" + +namespace OHOS { +namespace SignatureTools { + +ByteBufferDataSource::ByteBufferDataSource(class ByteBuffer& hapBuffer) + : DataSource(), bytebuffer(hapBuffer) +{ +} + +ByteBufferDataSource::~ByteBufferDataSource() +{ +} + +bool ByteBufferDataSource::HasRemaining() const +{ + return bytebuffer.HasRemaining(); +} + +int64_t ByteBufferDataSource::Remaining() const +{ + return static_cast(bytebuffer.Remaining()); +} + +void ByteBufferDataSource::Reset() +{ + bytebuffer.Clear(); +} + +bool ByteBufferDataSource::ReadDataAndDigestUpdate(const DigestParameter& digestParam, int32_t chunkSize) +{ + const unsigned char* chunk = reinterpret_cast(bytebuffer.GetBufferPtr() + + bytebuffer.GetPosition()); + bool res = VerifyHapOpensslUtils::DigestUpdate(digestParam, chunk, chunkSize); + if (res) { + bytebuffer.SetPosition(bytebuffer.GetPosition() + chunkSize); + } + return res; +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/common/src/digest_parameter.cpp b/hapsigntool_cpp/common/src/digest_parameter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5db1f463bac0d04951c513e77f483aba904885f9 --- /dev/null +++ b/hapsigntool_cpp/common/src/digest_parameter.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024-2024 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), ptrCtx(nullptr) +{ +} + +DigestParameter::~DigestParameter() +{ + if (ptrCtx != nullptr) { + EVP_MD_CTX_destroy(ptrCtx); + ptrCtx = 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; + ptrCtx = EVP_MD_CTX_create(); + EVP_MD_CTX_copy(ptrCtx, other.ptrCtx); +} + +DigestParameter& DigestParameter::operator = (const DigestParameter& other) +{ + if (ptrCtx != nullptr) { + EVP_MD_CTX_destroy(ptrCtx); + ptrCtx = nullptr; + } + digestOutputSizeBytes = other.digestOutputSizeBytes; + md = other.md; + ptrCtx = EVP_MD_CTX_create(); + EVP_MD_CTX_copy(ptrCtx, other.ptrCtx); + return *this; +} +} +} \ No newline at end of file diff --git a/hapsigntool_cpp/common/src/file_data_source.cpp b/hapsigntool_cpp/common/src/file_data_source.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ec0db9ce8685f676abdf3af5ef5b8db79946a3db --- /dev/null +++ b/hapsigntool_cpp/common/src/file_data_source.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024-2024 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_data_source.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { +FileDataSource::FileDataSource(RandomAccessFile& hapFile, + int64_t offset, int64_t size, int64_t position) + : DataSource(), hapFileRandomAccess(hapFile), fileOffset(offset), sourceSize(size), sourcePosition(position) +{ +} + +FileDataSource::~FileDataSource() +{ +} + +bool FileDataSource::HasRemaining() const +{ + return sourcePosition < sourceSize; +} + +int64_t FileDataSource::Remaining() const +{ + return sourceSize - sourcePosition; +} + +void FileDataSource::Reset() +{ + sourcePosition = 0; +} + +bool FileDataSource::ReadDataAndDigestUpdate(const DigestParameter& digestParam, int32_t chunkSize) +{ + if (!hapFileRandomAccess.ReadFileFromOffsetAndDigestUpdate(digestParam, chunkSize, + fileOffset + sourcePosition)) { + SIGNATURE_TOOLS_LOGE("ReadFileFromOffsetAndDigestUpdate failed"); + return false; + } + sourcePosition += chunkSize; + return true; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/common/src/random_access_file.cpp b/hapsigntool_cpp/common/src/random_access_file.cpp new file mode 100644 index 0000000000000000000000000000000000000000..25139c20607720a8a369fd2fe3dd464fa8f53b66 --- /dev/null +++ b/hapsigntool_cpp/common/src/random_access_file.cpp @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2024-2024 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 "securec.h" +#include "signature_info.h" +#include "signature_tools_log.h" +#include "verify_hap_openssl_utils.h" +#include "random_access_file.h" + +namespace OHOS { +namespace SignatureTools { +int32_t RandomAccessFile::memoryPageSize = sysconf(_SC_PAGESIZE); + +RandomAccessFile::RandomAccessFile() + : fd(-1), fileLength(0) +{ +} + +RandomAccessFile::~RandomAccessFile() +{ + if (fd != -1) { + close(fd); + } +} + +bool RandomAccessFile::Init(const std::string& filePath) +{ + fd = open(filePath.c_str(), O_RDWR); + if (fd == -1) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open file: " + filePath + " failed"); + return false; + } + + if (memoryPageSize <= 0) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, + "getting pagesize failed. memoryPageSize: " + std::to_string(memoryPageSize)); + return false; + } + + struct stat file_stat; + if (fstat(fd, &file_stat) == -1) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, + filePath + "get status failed"); + return false; + } + fileLength = file_stat.st_size; + + return true; +} + +int64_t RandomAccessFile::GetLength() const +{ + return fileLength; +} + +bool RandomAccessFile::CheckLittleEndian() +{ + union LittleEndian { + int32_t num; + char ch; + } t; + t.num = 1; + return (t.ch == 1); +} + +int32_t RandomAccessFile::DoMMap(int32_t bufCapacity, int64_t offset, MmapInfo& mmapInfo) +{ + if (!CheckLittleEndian()) { + SIGNATURE_TOOLS_LOGE("CheckLittleEndian: failed"); + return MMAP_FAILED; + } + + // Starting address for memory mapping + mmapInfo.mapAddr = reinterpret_cast(MAP_FAILED); + if (fd == -1) { + SIGNATURE_TOOLS_LOGE("random access file's fd is -1, the file is closed"); + return FILE_IS_CLOSE; + } + if (offset < 0 || offset > fileLength - bufCapacity) { + SIGNATURE_TOOLS_LOGE("offset is less than 0 OR read offset is out of range. offset: %" PRId64 + ", range: %" PRId64, offset, fileLength - bufCapacity); + return READ_OFFSET_OUT_OF_RANGE; + } + // Memory mapped file offset, 0 OR an integer multiple of 4K + mmapInfo.mmapPosition = (offset / memoryPageSize) * memoryPageSize; + // How many more bytes can be read from the current mapped memory page to find + mmapInfo.readMoreLen = static_cast(offset - mmapInfo.mmapPosition); + mmapInfo.mmapSize = bufCapacity + mmapInfo.readMoreLen; + mmapInfo.mapAddr = reinterpret_cast(mmap(nullptr, mmapInfo.mmapSize, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_POPULATE, fd, mmapInfo.mmapPosition)); + if (mmapInfo.mapAddr == MAP_FAILED) { + SIGNATURE_TOOLS_LOGE("mmap failed"); + return MMAP_FAILED; + } + return 0; +} + +int32_t RandomAccessFile::ReadFileFullyFromOffset(char buf[], int64_t offset, int64_t bufCapacity) +{ + if (buf == nullptr) { + SIGNATURE_TOOLS_LOGE("The dest buffer is null"); + return DEST_BUFFER_IS_NULL; + } + + MmapInfo mmapInfo; + int32_t ret = DoMMap(bufCapacity, offset, mmapInfo); + if (ret < 0) { + return ret; + } + + if (memcpy_s(buf, bufCapacity, mmapInfo.mapAddr + mmapInfo.readMoreLen, + mmapInfo.mmapSize - mmapInfo.readMoreLen) != EOK) { + munmap(mmapInfo.mapAddr, mmapInfo.mmapSize); + SIGNATURE_TOOLS_LOGE("memcpy_s error, errno: %d", IO_ERROR); + return MMAP_COPY_FAILED; + } + munmap(mmapInfo.mapAddr, mmapInfo.mmapSize); + return bufCapacity; +} + +int32_t RandomAccessFile::ReadFileFullyFromOffset(ByteBuffer& buffer, int64_t offset) +{ + if (!buffer.HasRemaining()) { + SIGNATURE_TOOLS_LOGE("The dest buffer has not remaining"); + return DEST_BUFFER_IS_NULL; + } + + MmapInfo mmapInfo; + int32_t bufCapacity = buffer.GetCapacity(); + int64_t ret = DoMMap(bufCapacity, offset, mmapInfo); + if (ret < 0) { + return ret; + } + + buffer.PutData(0, mmapInfo.mapAddr + mmapInfo.readMoreLen, bufCapacity); + munmap(mmapInfo.mapAddr, mmapInfo.mmapSize); + return bufCapacity; +} + +int32_t RandomAccessFile::WriteToFile(ByteBuffer& buffer, int64_t position, int64_t length) +{ + // write file, file length may change + int64_t remainLength = fileLength - position; + fileLength = (length <= remainLength) ? fileLength : (fileLength + (length - remainLength)); + // update file length + if (ftruncate(fd, fileLength) == -1) { + SIGNATURE_TOOLS_LOGE("RandomAccessFile ftruncate error: %s", strerror(errno)); + return IO_ERROR; + } + + int32_t bufCapacity = buffer.GetCapacity(); + if (bufCapacity == 0) { + SIGNATURE_TOOLS_LOGE("The dest buffer capacity is 0"); + return DEST_BUFFER_IS_NULL; + } + + MmapInfo mmapInfo; + + int32_t ret = DoMMap(bufCapacity, position, mmapInfo); + if (ret < 0) { + SIGNATURE_TOOLS_LOGE("DoMMap failed: %d", ret); + return ret; + } + + if (memcpy_s(mmapInfo.mapAddr + mmapInfo.readMoreLen, + mmapInfo.mmapSize - mmapInfo.readMoreLen, + buffer.GetBufferPtr(), bufCapacity) != RET_OK) { + SIGNATURE_TOOLS_LOGE("memcpy_s error, errno: %d", IO_ERROR); + return MMAP_COPY_FAILED; + } + munmap(mmapInfo.mapAddr, mmapInfo.mmapSize); + return bufCapacity; +} + +bool RandomAccessFile::ReadFileFromOffsetAndDigestUpdate(const DigestParameter& digestParam, + int32_t chunkSize, int64_t offset) +{ + MmapInfo mmapInfo; + int32_t ret = DoMMap(chunkSize, offset, mmapInfo); + if (ret < 0) { + SIGNATURE_TOOLS_LOGE("DoMMap failed: %d", ret); + return false; + } + unsigned char* content = reinterpret_cast(mmapInfo.mapAddr + mmapInfo.readMoreLen); + bool res = VerifyHapOpensslUtils::DigestUpdate(digestParam, content, chunkSize); + munmap(mmapInfo.mapAddr, mmapInfo.mmapSize); + return res; +} +} +} \ No newline at end of file diff --git a/hapsigntool_cpp/hap/config/.gitignore b/hapsigntool_cpp/hap/config/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..259148fa18f9fb7ef58563f4ff15fc7b172339fb --- /dev/null +++ b/hapsigntool_cpp/hap/config/.gitignore @@ -0,0 +1,32 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/hapsigntool_cpp/hap/config/include/signer_config.h b/hapsigntool_cpp/hap/config/include/signer_config.h new file mode 100644 index 0000000000000000000000000000000000000000..d22712544ff253f1eeca55d453d0ac8e2f852505 --- /dev/null +++ b/hapsigntool_cpp/hap/config/include/signer_config.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024-2024 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/hapsigntool_cpp/hap/config/src/signer_config.cpp b/hapsigntool_cpp/hap/config/src/signer_config.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b96f41fed183dc573bee9ac67439d3989a30faaf --- /dev/null +++ b/hapsigntool_cpp/hap/config/src/signer_config.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2024-2024 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/hapsigntool_cpp/hap/entity/.gitignore b/hapsigntool_cpp/hap/entity/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..259148fa18f9fb7ef58563f4ff15fc7b172339fb --- /dev/null +++ b/hapsigntool_cpp/hap/entity/.gitignore @@ -0,0 +1,32 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/hapsigntool_cpp/hap/entity/include/content_digest_algorithm.h b/hapsigntool_cpp/hap/entity/include/content_digest_algorithm.h new file mode 100644 index 0000000000000000000000000000000000000000..9586a9490815b85e11f963c9b792a577474273f1 --- /dev/null +++ b/hapsigntool_cpp/hap/entity/include/content_digest_algorithm.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2024-2024 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/hapsigntool_cpp/hap/entity/include/hw_block_data.h b/hapsigntool_cpp/hap/entity/include/hw_block_data.h new file mode 100644 index 0000000000000000000000000000000000000000..5ef2f768bcfca16b94d4b4d16f4c7e471679c417 --- /dev/null +++ b/hapsigntool_cpp/hap/entity/include/hw_block_data.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024-2024 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_HW_BLOCK_DATA_H +#define SIGNATRUETOOLS_HW_BLOCK_DATA_H + +#include + +namespace OHOS { +namespace SignatureTools { +class HwBlockData { +public: + HwBlockData(int32_t blockNum, int64_t blockStart); + + int32_t GetBlockNum(); + void SetBlockNum(int32_t blockNum); + int64_t GetBlockStart(); + void SetBlockStart(int64_t blockStart); + +private: + int32_t m_blockNum; + int64_t m_blockStart; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif \ No newline at end of file diff --git a/hapsigntool_cpp/hap/entity/include/hw_block_head.h b/hapsigntool_cpp/hap/entity/include/hw_block_head.h new file mode 100644 index 0000000000000000000000000000000000000000..8a397b3f3bcc3b305049309f4385799bd355e216 --- /dev/null +++ b/hapsigntool_cpp/hap/entity/include/hw_block_head.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024-2024 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_HW_BLOCK_HEAD_H +#define SIGNATRUETOOLS_HW_BLOCK_HEAD_H + +#include +#include + +namespace OHOS { +namespace SignatureTools { +class HwBlockHead { +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(char type, char tag, short length, int offset); + static std::vector GetBlockHeadLittleEndian(char type, char tag, int length, int offset); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif \ No newline at end of file diff --git a/hapsigntool_cpp/hap/entity/include/hw_sign_head.h b/hapsigntool_cpp/hap/entity/include/hw_sign_head.h new file mode 100644 index 0000000000000000000000000000000000000000..63ddb9e25ff8ab967f976ce70160a2935a082b17 --- /dev/null +++ b/hapsigntool_cpp/hap/entity/include/hw_sign_head.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024-2024 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_HW_SIGN_HEAD_H +#define SIGNATRUETOOLS_HW_SIGN_HEAD_H + +#include +#include + +namespace OHOS { +namespace SignatureTools { +class HwSignHead { +public: + HwSignHead(); + + std::vector GetSignHead(int subBlockSize); + static const int SIGN_HEAD_LEN; + static const std::string MAGIC; + static const std::string ELF_MAGIC; + static const std::string VERSION; + static const int32_t ELF_BLOCK_LEN; + static const int32_t BIN_BLOCK_LEN; + static std::vector GetSignHeadLittleEndian(int subBlockSize, int subBlockNum); + +private: + static const int NUM_OF_BLOCK; + static const int RESERVE_LENGTH; + static std::vector m_reserve; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif \ No newline at end of file diff --git a/hapsigntool_cpp/hap/entity/include/param_constants.h b/hapsigntool_cpp/hap/entity/include/param_constants.h new file mode 100644 index 0000000000000000000000000000000000000000..afca4b35d3e8a6e4f9ef149d3a0d9ec51ef2d034 --- /dev/null +++ b/hapsigntool_cpp/hap/entity/include/param_constants.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024-2024 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 constexpr int FILE_NAME_MIN_LENGTH = 2; + static const std::string DISABLE_SIGN_CODE; + static const std::string ENABLE_SIGN_CODE; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATURETOOLS_PARAM_CONSTANTS_H diff --git a/hapsigntool_cpp/hap/entity/include/sign_block_data.h b/hapsigntool_cpp/hap/entity/include/sign_block_data.h new file mode 100644 index 0000000000000000000000000000000000000000..c1e616cbfc222ce86e5308c719f22d3cb3d843cc --- /dev/null +++ b/hapsigntool_cpp/hap/entity/include/sign_block_data.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024-2024 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_BLOCK_DATA_H +#define SIGNATRUETOOLS_SIGN_BLOCK_DATA_H + +#include +#include + +#include "file_utils.h" + +namespace OHOS { +namespace SignatureTools { +class SignBlockData { +public: + SignBlockData(std::vector& signData, char type); + SignBlockData(std::string &signFile, char type); + + char GetType(); + std::vector GetBlockHead(); + void SetBlockHead(std::vector &blockHead); + std::vector GetSignData(); + std::string GetSignFile(); + long GetLen(); + bool GetByte(); + +private: + char m_type; + long m_len; + bool m_isByte; + std::vector m_blockHead; + std::vector m_signData; + std::string m_signFile; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif diff --git a/hapsigntool_cpp/hap/entity/include/sign_block_info.h b/hapsigntool_cpp/hap/entity/include/sign_block_info.h new file mode 100644 index 0000000000000000000000000000000000000000..9c575d0f5c72ea28007bb003bee36d837df0a496 --- /dev/null +++ b/hapsigntool_cpp/hap/entity/include/sign_block_info.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024-2024 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_SIGN_BLOCK_INFO_H +#define SIGNATURETOOLS_SIGN_BLOCK_INFO_H + +#include +#include + +#include "signing_block.h" + +namespace OHOS { +namespace SignatureTools { +class SignBlockInfo { +public: + SignBlockInfo(); + SignBlockInfo(bool needGenerateDigest); + +public: + std::unordered_map& GetSignBlockMap(); + std::vector GetFileDigest(); + void SetFileDigest(std::vector fileDigest); + std::vector GetRawDigest(); + void SetRawDigest(std::vector rawDigest); + bool GetNeedGenerateDigest(); + +private: + std::unordered_map m_signBlockMap; + std::vector m_fileDigest; + std::vector m_rawDigest; + bool m_needGenerateDigest; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif \ No newline at end of file diff --git a/hapsigntool_cpp/hap/entity/include/sign_content_info.h b/hapsigntool_cpp/hap/entity/include/sign_content_info.h new file mode 100644 index 0000000000000000000000000000000000000000..990342ed821f7fd59c15bbf7005450f67277739f --- /dev/null +++ b/hapsigntool_cpp/hap/entity/include/sign_content_info.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024-2024 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_CONTENT_INFO_H +#define SIGNATRUETOOLS_SIGN_CONTENT_INFO_H + +#include +#include +#include +#include + +namespace OHOS { +namespace SignatureTools { +class SignContentHash { +public: + SignContentHash(char type, char tag, short algId, int length, std::vector hash); + +public: + static const int CONTENT_HEAD_SIZE = 8; + char m_type; + char m_tag; + short m_algId; + int m_length; + std::vector m_hash; + int m_contentHashLen; +}; + +class SignContentInfo { +public: + SignContentInfo(); + +public: + void AddContentHashData(char type, char tag, short algId, int length, std::vector hash); + void AddHashData(SignContentHash signInfo); + std::vector GetByteContent(); + +private: + std::string m_version; + short m_size; + short m_numOfBlocks; + std::list m_hashData; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif \ No newline at end of file diff --git a/hapsigntool_cpp/hap/entity/include/signature_algorithm_helper.h b/hapsigntool_cpp/hap/entity/include/signature_algorithm_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..f818d1ce60b0f2ae1e83b96cb1b2d033235bfc91 --- /dev/null +++ b/hapsigntool_cpp/hap/entity/include/signature_algorithm_helper.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024-2024 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(SignatureAlgorithmId id_, std::string keyAlg_, ContentDigestAlgorithm digestAlg_, + std::pair sigParams_); + SignatureAlgorithmHelper& operator=(const SignatureAlgorithmHelper& other); + ~SignatureAlgorithmHelper(); + + static const SignatureAlgorithmHelper* FindById(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/hapsigntool_cpp/hap/entity/include/signature_block_tags.h b/hapsigntool_cpp/hap/entity/include/signature_block_tags.h new file mode 100644 index 0000000000000000000000000000000000000000..5aba056e81de9cf83790588288e2378530ba2b30 --- /dev/null +++ b/hapsigntool_cpp/hap/entity/include/signature_block_tags.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024-2024 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_SIGNATURE_BLOCK_TAGS_H +#define SIGNATRUETOOLS_SIGNATURE_BLOCK_TAGS_H + +namespace OHOS { +namespace SignatureTools { +class SignatureBlockTags { +public: + static const char DEFAULT = 0; + static const char HASH_ALL = 1; + static const char HASH_ROOT_1M = 0x80; + static const char HASH_ROOT_512K = 0x81; + static const char HASH_ROOT_256K = 0x82; + static const char HASH_ROOT_128K = 0x83; + static const char HASH_ROOT_64K = 0x84; + static const char HASH_ROOT_32K = 0x85; + static const char HASH_ROOT_16K = 0x86; + static const char HASH_ROOT_8K = 0x87; + static const char HASH_ROOT_4K = 0x88; + static const char HASH_BLOCK_1M = 0x90; + static const char HASH_BLOCK_512K = 0x91; + static const char HASH_BLOCK_256K = 0x92; + static const char HASH_BLOCK_128K = 0x93; + static const char HASH_BLOCK_64K = 0x94; + static const char HASH_BLOCK_32K = 0x95; + static const char HASH_BLOCK_16K = 0x96; + static const char HASH_BLOCK_8K = 0x97; + static const char HASH_BLOCK_4K = 0x98; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif \ No newline at end of file diff --git a/hapsigntool_cpp/hap/entity/include/signature_block_types.h b/hapsigntool_cpp/hap/entity/include/signature_block_types.h new file mode 100644 index 0000000000000000000000000000000000000000..f89fc4785ea5c88d16806d82cf15aa7f7423cc44 --- /dev/null +++ b/hapsigntool_cpp/hap/entity/include/signature_block_types.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024-2024 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_SIGNATURE_BLOCK_TYPES_H +#define SIGNATRUETOOLS_SIGNATURE_BLOCK_TYPES_H + +#include + +namespace OHOS { +namespace SignatureTools { +class SignatureBlockTypes { +public: + static const char SIGNATURE_BLOCK = 0; + static const char PROFILE_NOSIGNED_BLOCK = 1; + static const char PROFILE_SIGNED_BLOCK = 2; + static const char KEY_ROTATION_BLOCK = 3; + +public: + static char GetProfileBlockTypes(const std::string &isSigned); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif \ No newline at end of file diff --git a/hapsigntool_cpp/hap/entity/include/signing_block.h b/hapsigntool_cpp/hap/entity/include/signing_block.h new file mode 100644 index 0000000000000000000000000000000000000000..e4a5bb436f55359e0046b7308be9388d7e0d5f29 --- /dev/null +++ b/hapsigntool_cpp/hap/entity/include/signing_block.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024-2024 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_SIGNING_BLOCK_H +#define SIGNATRUETOOLS_SIGNING_BLOCK_H + +#include +#include + +#include "file_utils.h" + +namespace OHOS { +namespace SignatureTools { +class SigningBlock { +public: + SigningBlock(int32_t type, std::vector value); + SigningBlock(int32_t type, std::vector value, int64_t offset); + + int32_t GetLength(); + std::vector GetValue(); + int64_t GetOffset(); + +private: + int32_t m_type = 0; + int32_t m_length = 0; + std::vector m_value; + int64_t m_offset = 0; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif diff --git a/hapsigntool_cpp/hap/entity/src/content_digest_algorithm.cpp b/hapsigntool_cpp/hap/entity/src/content_digest_algorithm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0f219b367b80a532dd867bb53892ee1c807a5bc3 --- /dev/null +++ b/hapsigntool_cpp/hap/entity/src/content_digest_algorithm.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024-2024 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/hapsigntool_cpp/hap/entity/src/hw_block_data.cpp b/hapsigntool_cpp/hap/entity/src/hw_block_data.cpp new file mode 100644 index 0000000000000000000000000000000000000000..711a40b94c9d0183386d9837fd08968c51fbe21a --- /dev/null +++ b/hapsigntool_cpp/hap/entity/src/hw_block_data.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024-2024 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 "hw_block_data.h" + +namespace OHOS { +namespace SignatureTools { + +HwBlockData::HwBlockData(int32_t blockNum, int64_t blockStart) +{ + m_blockNum = blockNum; + m_blockStart = blockStart; +} + +int32_t HwBlockData::GetBlockNum() +{ + return m_blockNum; +} + +void HwBlockData::SetBlockNum(int32_t blockNum) +{ + m_blockNum = blockNum; +} + +int64_t HwBlockData::GetBlockStart() +{ + return m_blockStart; +} + +void HwBlockData::SetBlockStart(int64_t blockStart) +{ + m_blockStart = blockStart; +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/hap/entity/src/hw_block_head.cpp b/hapsigntool_cpp/hap/entity/src/hw_block_head.cpp new file mode 100644 index 0000000000000000000000000000000000000000..71116ea202c2d59b6f06fae1b8eae40d387027e7 --- /dev/null +++ b/hapsigntool_cpp/hap/entity/src/hw_block_head.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024-2024 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 "hw_block_head.h" +#include "byte_buffer.h" +#include "hw_sign_head.h" + +namespace OHOS { +namespace SignatureTools { + +int HwBlockHead::GetBlockLen() +{ + return BLOCK_LEN; +} + +int HwBlockHead::GetElfBlockLen() +{ + return ELF_BLOCK_LEN; +} + +std::string HwBlockHead::GetBlockHead(char type, char tag, short length, int offset) +{ + std::vector tmpVec; + tmpVec.push_back(type); + tmpVec.push_back(tag); + tmpVec.push_back((length >> BIT_SIZE) & 0xff); + tmpVec.push_back(length & 0xff); + tmpVec.push_back((offset >> TRIPLE_BIT_SIZE) & 0xff); + tmpVec.push_back((offset >> DOUBLE_BIT_SIZE) & 0xff); + tmpVec.push_back((offset >> BIT_SIZE) & 0xff); + tmpVec.push_back(offset & 0xff); + + return std::string(tmpVec.begin(), tmpVec.end()); +} + +std::vector HwBlockHead::GetBlockHeadLittleEndian(char type, char tag, int length, int offset) +{ + ByteBuffer bf = ByteBuffer(HwBlockHead::ELF_BLOCK_LEN); + bf.PutByte(type); + bf.PutByte(tag); + bf.PutByte(0); + bf.PutByte(0); + bf.PutInt32(length); + bf.PutInt32(offset); + int8_t ret[HwBlockHead::ELF_BLOCK_LEN]; + bf.GetData(0, ret, HwBlockHead::ELF_BLOCK_LEN); + std::vector byte(ret, ret + HwBlockHead::ELF_BLOCK_LEN); + return byte; +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/hap/entity/src/hw_sign_head.cpp b/hapsigntool_cpp/hap/entity/src/hw_sign_head.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0852ab1075d1cd893b8a3a0535b90c84f9f1929c --- /dev/null +++ b/hapsigntool_cpp/hap/entity/src/hw_sign_head.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2024-2024 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 "byte_buffer.h" +#include "byte_array_utils.h" +#include "signature_tools_log.h" +#include "hw_sign_head.h" + +namespace OHOS { +namespace SignatureTools { + +const int HwSignHead::SIGN_HEAD_LEN = 32; +const std::string HwSignHead::MAGIC = "hw signed app "; +const std::string HwSignHead::ELF_MAGIC = "elf sign block "; +const std::string HwSignHead::VERSION = "1000"; +const int HwSignHead::NUM_OF_BLOCK = 2; +const int HwSignHead::RESERVE_LENGTH = 4; +const int32_t HwSignHead::ELF_BLOCK_LEN = 12; +const int32_t HwSignHead::BIN_BLOCK_LEN = 8; +std::vector HwSignHead::m_reserve = std::vector(HwSignHead::RESERVE_LENGTH, 0); + +HwSignHead::HwSignHead() +{ +} + +std::vector HwSignHead::GetSignHead(int subBlockSize) +{ + int size = subBlockSize; + std::vector signHead(SIGN_HEAD_LEN, 0); + int start = 0; + start = ByteArrayUtils::InsertCharToByteArray(signHead, start, MAGIC); + if (start < 0) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "InsertCharToByteArray failed."); + return std::vector(); + } + start = ByteArrayUtils::InsertCharToByteArray(signHead, start, VERSION); + if (start < 0) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "InsertCharToByteArray failed."); + return std::vector(); + } + start = ByteArrayUtils::InsertIntToByteArray(signHead, start, size); + if (start < 0) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "InsertIntToByteArray failed."); + return std::vector(); + } + start = ByteArrayUtils::InsertIntToByteArray(signHead, start, NUM_OF_BLOCK); + if (start < 0) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "InsertIntToByteArray failed."); + return std::vector(); + } + start = ByteArrayUtils::InsertCharToByteArray(signHead, start, std::string(m_reserve.begin(), m_reserve.end())); + if (start < 0) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "InsertCharToByteArray failed."); + return std::vector(); + } + return signHead; +} + +std::vector HwSignHead::GetSignHeadLittleEndian(int subBlockSize, int subBlockNum) +{ + ByteBuffer bf = ByteBuffer(HwSignHead::SIGN_HEAD_LEN); + for (char c : HwSignHead::ELF_MAGIC) { + bf.PutByte(c); + } + for (char c : HwSignHead::VERSION) { + bf.PutByte(c); + } + bf.PutInt32(subBlockSize); + bf.PutInt32(subBlockNum); + for (char c : HwSignHead::m_reserve) { + bf.PutByte(c); + } + int8_t ret[HwSignHead::SIGN_HEAD_LEN]; + bf.GetData(0, ret, HwSignHead::SIGN_HEAD_LEN); + std::vector byte(ret, ret + HwSignHead::SIGN_HEAD_LEN); + + return byte; +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/hap/entity/src/param_constants.cpp b/hapsigntool_cpp/hap/entity/src/param_constants.cpp new file mode 100644 index 0000000000000000000000000000000000000000..afa4c64725196eb37552021469843414613d083e --- /dev/null +++ b/hapsigntool_cpp/hap/entity/src/param_constants.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024-2024 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::DISABLE_SIGN_CODE = "0"; +const std::string ParamConstants::ENABLE_SIGN_CODE = "1"; +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/hap/entity/src/sign_block_data.cpp b/hapsigntool_cpp/hap/entity/src/sign_block_data.cpp new file mode 100644 index 0000000000000000000000000000000000000000..05efa28f82950fccf0ff42e9ac6c450bab60e54a --- /dev/null +++ b/hapsigntool_cpp/hap/entity/src/sign_block_data.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024-2024 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_block_data.h" + +namespace OHOS { +namespace SignatureTools { + +SignBlockData::SignBlockData(std::vector& signData, char type) +{ + m_signData = signData; + m_type = type; + m_len = signData.size(); + m_isByte = true; +} + +SignBlockData::SignBlockData(std::string& signFile, char type) +{ + m_signFile = signFile; + m_type = type; + m_len = FileUtils::GetFileLen(signFile); + m_isByte = false; +} + +char SignBlockData::GetType() +{ + return m_type; +} + +std::vector SignBlockData::GetBlockHead() +{ + return m_blockHead; +} + +void SignBlockData::SetBlockHead(std::vector& blockHead) +{ + m_blockHead = blockHead; +} + +std::vector SignBlockData::GetSignData() +{ + return m_signData; +} + +std::string SignBlockData::GetSignFile() +{ + return m_signFile; +} + +long SignBlockData::GetLen() +{ + return m_len; +} + +bool SignBlockData::GetByte() +{ + return m_isByte; +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/hap/entity/src/sign_block_info.cpp b/hapsigntool_cpp/hap/entity/src/sign_block_info.cpp new file mode 100644 index 0000000000000000000000000000000000000000..545e9551b905f4c381b44b1bf8620c0f2e17ab92 --- /dev/null +++ b/hapsigntool_cpp/hap/entity/src/sign_block_info.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024-2024 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_block_info.h" + +namespace OHOS { +namespace SignatureTools { + +SignBlockInfo::SignBlockInfo() +{ +} + +SignBlockInfo::SignBlockInfo(bool needGenerateDigest) +{ + m_needGenerateDigest = needGenerateDigest; +} + +std::unordered_map& SignBlockInfo::GetSignBlockMap() +{ + return m_signBlockMap; +} + +std::vector SignBlockInfo::GetFileDigest() +{ + return m_fileDigest; +} + +void SignBlockInfo::SetFileDigest(std::vector fileDigest) +{ + m_fileDigest = fileDigest; +} + +std::vector SignBlockInfo::GetRawDigest() +{ + return m_rawDigest; +} + +void SignBlockInfo::SetRawDigest(std::vector rawDigest) +{ + m_rawDigest = rawDigest; +} + +bool SignBlockInfo::GetNeedGenerateDigest() +{ + return m_needGenerateDigest; +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/hap/entity/src/sign_content_info.cpp b/hapsigntool_cpp/hap/entity/src/sign_content_info.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a111d4f7eed2668941adcd6f32039addf333584d --- /dev/null +++ b/hapsigntool_cpp/hap/entity/src/sign_content_info.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2024-2024 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_content_info.h" +#include "byte_array_utils.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { + +SignContentHash::SignContentHash(char type, char tag, short algId, int length, std::vector hash) +{ + m_type = type; + m_tag = tag; + m_algId = algId; + m_length = length; + m_hash = hash; + m_contentHashLen = CONTENT_HEAD_SIZE + hash.size(); +} + +SignContentInfo::SignContentInfo() +{ + m_version = "1000"; + m_size = SignContentHash::CONTENT_HEAD_SIZE; + m_numOfBlocks = 0; +} + +void SignContentInfo::AddContentHashData(char type, char tag, short algId, int length, std::vector hash) +{ + SignContentHash signInfo(type, tag, algId, length, hash); + AddHashData(signInfo); +} + +void SignContentInfo::AddHashData(SignContentHash signInfo) +{ + m_hashData.push_back(signInfo); + ++m_numOfBlocks; + m_size += signInfo.m_contentHashLen; +} + +std::vector SignContentInfo::GetByteContent() +{ + std::vector ret(m_size, 0); + int index = 0; + + index = ByteArrayUtils::InsertCharToByteArray(ret, index, m_version); + if (index < 0) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "InsertCharToByteArray failed."); + return std::vector(); + } + + index = ByteArrayUtils::InsertShortToByteArray(ret, ret.size(), index, m_size); + if (index < 0) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "InsertShortToByteArray failed."); + return std::vector(); + } + + index = ByteArrayUtils::InsertShortToByteArray(ret, ret.size(), index, m_numOfBlocks); + if (index < 0) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "InsertShortToByteArray failed."); + return std::vector(); + } + + for (const auto& tmp : m_hashData) { + ret[index] = tmp.m_type; + index++; + ret[index] = tmp.m_tag; + index++; + index = ByteArrayUtils::InsertShortToByteArray(ret, ret.size(), index, tmp.m_algId); + index = ByteArrayUtils::InsertIntToByteArray(ret, index, tmp.m_length); + index = ByteArrayUtils::InsertByteToByteArray(ret, index, tmp.m_hash, tmp.m_hash.size()); + if (index < 0) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "InsertShortToByteArray failed."); + return std::vector(); + } + } + return ret; +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/hap/entity/src/signature_algorithm_helper.cpp b/hapsigntool_cpp/hap/entity/src/signature_algorithm_helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f6af5064e116e5c641563a13057f4dcfe343c0a4 --- /dev/null +++ b/hapsigntool_cpp/hap/entity/src/signature_algorithm_helper.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024-2024 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(SignatureAlgorithmId id_, std::string keyAlg_, + ContentDigestAlgorithm digestAlg_, + 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(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/hapsigntool_cpp/hap/entity/src/signature_block_tags.cpp b/hapsigntool_cpp/hap/entity/src/signature_block_tags.cpp new file mode 100644 index 0000000000000000000000000000000000000000..365b34aa47a03bfefd7d1aaee8e80236c1bad4a6 --- /dev/null +++ b/hapsigntool_cpp/hap/entity/src/signature_block_tags.cpp @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2024-2024 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_block_tags.h" + +using namespace OHOS::SignatureTools; \ No newline at end of file diff --git a/hapsigntool_cpp/hap/entity/src/signature_block_types.cpp b/hapsigntool_cpp/hap/entity/src/signature_block_types.cpp new file mode 100644 index 0000000000000000000000000000000000000000..05c07c4fb573e9b37f1ad10299a928e1921d1364 --- /dev/null +++ b/hapsigntool_cpp/hap/entity/src/signature_block_types.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024-2024 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_block_types.h" + +using namespace OHOS::SignatureTools; + +char SignatureBlockTypes::GetProfileBlockTypes(const std::string& isSigned) +{ + if (!isSigned.empty() && 0 == isSigned.compare("0")) { + return PROFILE_NOSIGNED_BLOCK; + } + if (!isSigned.empty() && 0 == isSigned.compare("1")) { + return PROFILE_SIGNED_BLOCK; + } + return PROFILE_NOSIGNED_BLOCK; +} \ No newline at end of file diff --git a/hapsigntool_cpp/hap/entity/src/signing_block.cpp b/hapsigntool_cpp/hap/entity/src/signing_block.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0f273388dc85fc6067bef7cdbb53b60598331d33 --- /dev/null +++ b/hapsigntool_cpp/hap/entity/src/signing_block.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024-2024 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 "signing_block.h" + +namespace OHOS { +namespace SignatureTools { + +SigningBlock::SigningBlock(int32_t type, std::vector value) +{ + m_type = type; + m_length = value.size(); + m_value = value; +} + +SigningBlock::SigningBlock(int32_t type, std::vector value, int64_t offset) +{ + m_type = type; + m_length = value.size(); + m_value = value; + m_offset = offset; +} + +int32_t SigningBlock::GetLength() +{ + return m_length; +} + +std::vector SigningBlock::GetValue() +{ + return m_value; +} + +int64_t SigningBlock::GetOffset() +{ + return m_offset; +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/hap/provider/.gitignore b/hapsigntool_cpp/hap/provider/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..259148fa18f9fb7ef58563f4ff15fc7b172339fb --- /dev/null +++ b/hapsigntool_cpp/hap/provider/.gitignore @@ -0,0 +1,32 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/hapsigntool_cpp/hap/provider/include/local_sign_provider.h b/hapsigntool_cpp/hap/provider/include/local_sign_provider.h new file mode 100644 index 0000000000000000000000000000000000000000..82c71c7ba0ff68925feb85d0fedecfa7c5e6cae2 --- /dev/null +++ b/hapsigntool_cpp/hap/provider/include/local_sign_provider.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024-2024 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/hapsigntool_cpp/hap/provider/include/remote_sign_provider.h b/hapsigntool_cpp/hap/provider/include/remote_sign_provider.h new file mode 100644 index 0000000000000000000000000000000000000000..ae3ff6e2f89ca67c173cb1d02fc838ff34e93986 --- /dev/null +++ b/hapsigntool_cpp/hap/provider/include/remote_sign_provider.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024-2024 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: + static void* handle; + + RemoteSignProvider() = default; + ~RemoteSignProvider(); + 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/hapsigntool_cpp/hap/provider/include/sign_provider.h b/hapsigntool_cpp/hap/provider/include/sign_provider.h new file mode 100644 index 0000000000000000000000000000000000000000..685593925e632b0cf5af1a49dfba597581b0efab --- /dev/null +++ b/hapsigntool_cpp/hap/provider/include/sign_provider.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2024-2024 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 "hap_utils.h" +#include "hap_verify_result.h" +#include "hap_signer_block_utils.h" +#include "sign_hap.h" +#include "signature_tools_log.h" +#include "signer_config.h" +#include "param_constants.h" +#include "byte_buffer.h" +#include "data_source.h" +#include "random_access_file_input.h" +#include "random_access_file_output.h" +#include "random_access_file.h" +#include "zip_entry_header.h" +#include "zip_signer.h" +#include "zip_data_input.h" +#include "zip_utils.h" +#include "code_signing.h" +#include "byte_buffer_data_source.h" +#include "pkcs7_data.h" +#include "profile_verify.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 SignBin(Options* options); + virtual std::optional GetCrl(); + virtual bool CheckParams(Options* options); + virtual bool CheckInputCertMatchWithProfile(X509* inputCert, X509* certInProfile)const; + +protected: + struct DataSourceContents { + DataSource* beforeCentralDir = nullptr; + ByteBufferDataSource* centralDir = nullptr; + ByteBufferDataSource* endOfCentralDir = nullptr; + ByteBuffer cDByteBuffer; + std::pair eocdPair; + int64_t cDOffset = 0LL; + ~DataSourceContents() + { + delete beforeCentralDir; + delete centralDir; + delete endOfCentralDir; + } + }; + + 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; + bool CheckSignCode(); + int LoadOptionalBlocks(); + bool CheckCompatibleVersion(); + std::vector optionalBlocks; + std::map signParams = std::map(); + +private: + int CheckParmaAndInitConfig(SignerConfig& config, Options* options, std::string& suffix); + + fileIOTuple PrepareIOStreams(const std::string& inputPath, const std::string& outputPath, bool& ret); + + bool InitZipOutput(std::shared_ptr outputHap, std::shared_ptr zip, + std::shared_ptr, std::shared_ptrtmpOutput, std::string path); + + bool PrintErrorLog(const std::string& log, const int& errorCode, std::string path = ""); + + bool InitSigerConfig(SignerConfig& signerConfig, STACK_OF(X509)* publicCerts, Options* options); + + bool DoAfterSign(bool isPathOverlap, std::string tmpOutputFile, std::string inputFilePath); + + bool CreateSignerConfigs(STACK_OF(X509)* certificates, const std::optional& crl, + Options* options, SignerConfig&); + + bool CopyFileAndAlignment(std::ifstream& input, std::ofstream& tmpOutput, int alignment, ZipSigner& zip); + + bool CheckSignatureAlg(); + + static bool CheckStringToint(const std::string& in, int& out); + 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); + + bool AppendCodeSignBlock(SignerConfig* signerConfig, std::string outputFilePath, + const std::string& suffix, int64_t centralDirectoryOffset, ZipSigner& zip); + bool OutputSignedFile(RandomAccessFile* outputHap, long centralDirectoryOffset, + ByteBuffer& signingBlock, ByteBufferDataSource* centralDirectory, ByteBuffer& eocdBuffer); + + bool InitDataSourceContents(RandomAccessFile& outputHap, DataSourceContents& dataSrcContents); + +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/hapsigntool_cpp/hap/provider/src/local_sign_provider.cpp b/hapsigntool_cpp/hap/provider/src/local_sign_provider.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b63038de699bb3770c94c76e157e98985130d76c --- /dev/null +++ b/hapsigntool_cpp/hap/provider/src/local_sign_provider.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2024-2024 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" + +namespace OHOS { +namespace SignatureTools { +std::optional LocalSignProvider::GetCrl() +{ + return std::optional(); +} + +bool LocalSignProvider::CheckParams(Options* options) +{ + bool flag = false; + 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); + for (auto it = options->begin(); it != options->end(); it++) { + flag = (paramSet.find(it->first) != paramSet.end()); + if (flag) { + size_t size = it->first.size(); + std::string str = it->first.substr(size - 3); + if (str == "Pwd") { + std::string strPwd = options->GetChars(it->first); + signParams.insert(std::make_pair(it->first, strPwd)); + } else { + signParams.insert(std::make_pair(it->first, options->GetString(it->first))); + } + } + } + if (!CheckSignCode()) { + SIGNATURE_TOOLS_LOGE("signCode Parameter must 0 or 1"); + return false; + } + flag = !CheckPublicKeyPath(); + if (flag) { + 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 "); + publicKeyFile.close(); + return false; + } + publicKeyFile.close(); + return true; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/hap/provider/src/remote_sign_provider.cpp b/hapsigntool_cpp/hap/provider/src/remote_sign_provider.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6d2740b37d1a725e3ccc46d394de4a8a059ca363 --- /dev/null +++ b/hapsigntool_cpp/hap/provider/src/remote_sign_provider.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2024-2024 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 { +void* RemoteSignProvider::handle = nullptr; +RemoteSignProvider::~RemoteSignProvider() +{ + if (handle) { + if (dlclose(handle) != 0) { + SIGNATURE_TOOLS_LOGE("dlclose() %s", dlerror()); + } + } +} + +bool RemoteSignProvider::CheckParams(Options* options) +{ + bool flag = false; + if (!SignProvider::CheckParams(options)) { + SIGNATURE_TOOLS_LOGE("SignProvider::Parameter check failed !"); + return false; + } + 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++) { + flag = (paramSet.find(it->first) != paramSet.end()); + if (flag) { + size_t size = it->first.size(); + std::string str = it->first.substr(size - 3); + if (str == "Pwd") { + std::string strPwd = options->GetChars(it->first); + strPwd = ""; + signParams.insert(std::make_pair(it->first, strPwd)); + } else { + signParams.insert(std::make_pair(it->first, options->GetString(it->first))); + } + } + } + for (const auto& param : paramFileds) { + flag = (signParams.find(param) == signParams.end()); + if (flag) { + 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, + "Check Input Cert Match With Profile failed, param error"); + 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, + "Check Input Cert Match With Profile failed, subject name is not compare"); + 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, + "Check Input Cert Match With Profile failed, issuer name is not compare"); + 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, + "Check Input Cert Match With Profile failed, serial Number is not compare"); + 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, + "Check Input Cert Match With Profile failed, pubkey is not compare"); + return false; + } + if (!pkey1 || !pkey2) { + PrintErrorNumberMsg("CERTIFICATE_ERROR", CERTIFICATE_ERROR, + "Check Input Cert Match With Profile failed,have 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/hapsigntool_cpp/hap/provider/src/sign_provider.cpp b/hapsigntool_cpp/hap/provider/src/sign_provider.cpp new file mode 100644 index 0000000000000000000000000000000000000000..de2d58ff1312468bc9a4b5a73f8e5eca10494c97 --- /dev/null +++ b/hapsigntool_cpp/hap/provider/src/sign_provider.cpp @@ -0,0 +1,830 @@ +/* + * Copyright (c) 2024-2024 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 "sign_bin.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::PrintErrorLog(const std::string& log, const int& errorCode, std::string path) +{ + SIGNATURE_TOOLS_LOGE("%s", std::string("(Error Code: " + std::to_string(errorCode) + ")" + log).c_str()); + if (path != "") { + remove(path.c_str()); + } + return false; +} + +bool SignProvider::InitSigerConfig(SignerConfig& signerConfig, STACK_OF(X509)* publicCerts, Options* options) +{ + std::optional crl = GetCrl(); + if (!CreateSignerConfigs(publicCerts, crl, options, signerConfig)) { + SIGNATURE_TOOLS_LOGE("[SignHap] create Signer Configs failed"); + return false; + } + int CompatibleVersion; + if (!CheckStringToint(signParams.at(ParamConstants::PARAM_BASIC_COMPATIBLE_VERSION), CompatibleVersion)) { + SIGNATURE_TOOLS_LOGE("[SignHap] CompatibleVersion String To int failed"); + return false; + } + signerConfig.SetCompatibleVersion(CompatibleVersion); + return true; +} + +int SignProvider::CheckParmaAndInitConfig(SignerConfig& signerConfig, Options* options, std::string& suffix) +{ + STACK_OF(X509)* publicCerts = nullptr; + int ret = GetX509Certificates(options, &publicCerts); + if (ret != RET_OK) { + sk_X509_pop_free(publicCerts, X509_free); + SIGNATURE_TOOLS_LOGE("SIGNHAP_ERROR get X509 Certificates failed"); + return ret; + } + if (!CheckCompatibleVersion()) { + sk_X509_pop_free(publicCerts, X509_free); + SIGNATURE_TOOLS_LOGE("check Compatible Version failed!!"); + return COMMAND_PARAM_ERROR; + } + if (!InitSigerConfig(signerConfig, publicCerts, options)) { + SIGNATURE_TOOLS_LOGE("create Signer Configs failed"); + return COMMAND_PARAM_ERROR; + } + std::string inputFilePath = signParams.at(ParamConstants::PARAM_BASIC_INPUT_FILE); + suffix = FileUtils::GetSuffix(inputFilePath); + if (suffix == "") { + SIGNATURE_TOOLS_LOGE("hap format error pleass check!!"); + return COMMAND_PARAM_ERROR; + } + return RET_OK; +} + +fileIOTuple SignProvider::PrepareIOStreams(const std::string& inputPath, + const std::string& outputPath, bool& ret) +{ + std::shared_ptr inputFile = nullptr; + std::shared_ptr outputFile = nullptr; + std::string tmpOutputFilePath; + ret = false; + inputFile = std::make_shared(inputPath, std::ios::binary); + if (!inputFile->good()) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, + inputPath + " open failed"); + return {nullptr, nullptr, ""}; + } + if (inputPath == outputPath) { + std::filesystem::path filePath = outputPath; + std::filesystem::path directory = filePath.parent_path(); + std::string strDirectory = directory; + tmpOutputFilePath = strDirectory + '/' + std::string("signedHap") + "." + "hap"; + outputFile = std::make_shared(tmpOutputFilePath, std::ios::binary | std::ios::trunc); + if (!outputFile->good()) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, + tmpOutputFilePath + " open failed"); + return {nullptr, nullptr, ""}; + } + ret = true; + } else { + outputFile = std::make_shared(outputPath, std::ios::binary | std::ios::trunc); + if (!outputFile->good()) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, + outputPath + " open failed"); + return {nullptr, nullptr, ""}; + } + tmpOutputFilePath = outputPath; + } + return {inputFile, outputFile, tmpOutputFilePath}; +} + +bool SignProvider::InitZipOutput(std::shared_ptr outputHap, + std::shared_ptr zip, + std::shared_ptr inputStream, + std::shared_ptrtmpOutput, + std::string Path) +{ + int alignment; + if (!CheckStringToint(signParams.at(ParamConstants::PARAM_BASIC_ALIGNMENT), alignment)) { + SIGNATURE_TOOLS_LOGE("[signHap] alignment String To int failed"); + inputStream->close(); + tmpOutput->close(); + remove(Path.c_str()); + return false; + } + + if (!CopyFileAndAlignment(*inputStream, *tmpOutput, alignment, *zip)) { + SIGNATURE_TOOLS_LOGE("[signHap] copy File And Alignment failed"); + inputStream->close(); + tmpOutput->close(); + remove(Path.c_str()); + return false; + } + + inputStream->close(); + tmpOutput->flush(); + tmpOutput->close(); + if (!outputHap->Init(Path)) { + SIGNATURE_TOOLS_LOGE("[signHap] init outputFile failed %s", Path.c_str()); + remove(Path.c_str()); + return false; + } + return true; +} + +bool SignProvider::InitDataSourceContents(RandomAccessFile& outputHap, DataSourceContents& dataSrcContents) +{ + std::shared_ptr outputHapIn = std::make_shared(outputHap); + // get eocd bytebuffer and eocd offset + if (!HapSignerBlockUtils::FindEocdInHap(outputHap, dataSrcContents.eocdPair)) { + PrintErrorNumberMsg("ZIP_ERROR", ZIP_ERROR, "eocd is not found in hap"); + return false; + } + dataSrcContents.endOfCentralDir = new ByteBufferDataSource(dataSrcContents.eocdPair.first); + if (!dataSrcContents.endOfCentralDir) { + return false; + } + + // get cd offset + if (!HapSignerBlockUtils::GetCentralDirectoryOffset(dataSrcContents.eocdPair.first, + dataSrcContents.eocdPair.second, dataSrcContents.cDOffset)) { + PrintErrorNumberMsg("ZIP_ERROR", ZIP_ERROR, "get central directory offset failed"); + return false; + } + + SIGNATURE_TOOLS_LOGI("Central Directory Offset is %" PRId64, dataSrcContents.cDOffset); + + // get beforeCentralDir + dataSrcContents.beforeCentralDir = outputHapIn->Slice(0, dataSrcContents.cDOffset); + if (!dataSrcContents.beforeCentralDir) { + return false; + } + + // get cd size + long cDSize; + if (!HapSignerBlockUtils::GetCentralDirectorySize(dataSrcContents.eocdPair.first, cDSize)) { + PrintErrorNumberMsg("ZIP_ERROR", ZIP_ERROR, "get central directory size failed"); + return false; + } + + // get cd buffer + dataSrcContents.cDByteBuffer = outputHapIn->CreateByteBuffer(dataSrcContents.cDOffset, cDSize); + if (dataSrcContents.cDByteBuffer.GetCapacity() == 0) { + return false; + } + dataSrcContents.centralDir = new ByteBufferDataSource(dataSrcContents.cDByteBuffer); + if (!dataSrcContents.centralDir) { + return false; + } + return true; +} + +bool SignProvider::Sign(Options* options) +{ + bool isPathOverlap = false; + SignerConfig signerConfig; + std::string suffix; + if (CheckParmaAndInitConfig(signerConfig, options, suffix) != RET_OK) { + return PrintErrorLog("Check Parma And Init Config failed", COMMAND_PARAM_ERROR); + } + // Since CheckParmaAndInitConfig has already validated all parameters, it is possible to directly use at + std::string inputFilePath = signParams.at(ParamConstants::PARAM_BASIC_INPUT_FILE); + auto [inputStream, tmpOutput, tmpOutputFilePath] = PrepareIOStreams( + inputFilePath, + signParams.at(ParamConstants::PARAM_BASIC_OUTPUT_FILE), isPathOverlap); + + if (!inputStream || !tmpOutput) { + return PrintErrorLog("[signHap] Prepare IO Streams failed", IO_ERROR); + } + + std::shared_ptr zip = std::make_shared(); + std::shared_ptr outputHap = std::make_shared(); + if (!InitZipOutput(outputHap, zip, inputStream, tmpOutput, tmpOutputFilePath)) { + return PrintErrorLog("[signHap] Init Zip Output failed", IO_ERROR); + } + + DataSourceContents dataSrcContents; + if (!InitDataSourceContents(*outputHap, dataSrcContents)) { + return PrintErrorLog("[signHap] Init Data Source Contents failed", ZIP_ERROR, tmpOutputFilePath); + } + + DataSource* contents[] = {dataSrcContents.beforeCentralDir, + dataSrcContents.centralDir, dataSrcContents.endOfCentralDir + }; + if (!AppendCodeSignBlock(&signerConfig, tmpOutputFilePath, suffix, dataSrcContents.cDOffset, *zip)) { + return PrintErrorLog("[SignCode] AppendCodeSignBlock failed", SIGN_ERROR, tmpOutputFilePath); + } + + ByteBuffer signingBlock; + if (!SignHap::Sign(contents, sizeof(contents) / sizeof(contents[0]), signerConfig, optionalBlocks, + signingBlock)) { + return PrintErrorLog("[SignHap] SignHap Sign failed.", SIGN_ERROR, tmpOutputFilePath); + } + + int64_t newCentralDirectoryOffset = dataSrcContents.cDOffset + signingBlock.GetCapacity(); + SIGNATURE_TOOLS_LOGI("new Central Directory Offset is %" PRId64, newCentralDirectoryOffset); + dataSrcContents.eocdPair.first.SetPosition(0); + if (!ZipUtils::SetCentralDirectoryOffset(dataSrcContents.eocdPair.first, newCentralDirectoryOffset)) { + return PrintErrorLog("[SignHap] Set Central Directory Offset.", ZIP_ERROR, tmpOutputFilePath); + } + + if (!OutputSignedFile(outputHap.get(), dataSrcContents.cDOffset, signingBlock, dataSrcContents.centralDir, + dataSrcContents.eocdPair.first)) { + return PrintErrorLog("[SignHap] write output signed file failed.", ZIP_ERROR, tmpOutputFilePath); + } + return DoAfterSign(isPathOverlap, tmpOutputFilePath, inputFilePath); +} + +bool SignProvider::SignElf(Options* options) +{ + bool isPathOverlap = false; + 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; + } + if (!CheckCompatibleVersion()) { + sk_X509_pop_free(publicCerts, X509_free); + SIGNATURE_TOOLS_LOGE("[SignElf] check Compatible Version failed!!"); + return false; + } + + std::string inputFilePath = signParams.at(ParamConstants::PARAM_BASIC_INPUT_FILE); + + auto [inputStream, tmpOutput, tmpOutputFilePath] = + PrepareIOStreams(inputFilePath, + signParams.at(ParamConstants::PARAM_BASIC_OUTPUT_FILE), + isPathOverlap); + + if (!inputStream || !tmpOutput) { + sk_X509_pop_free(publicCerts, X509_free); + SIGNATURE_TOOLS_LOGE("[signElf] Prepare IO Streams failed"); + 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::SignBin(Options* options) +{ + STACK_OF(X509)* x509Certificates = nullptr; + int ret = GetX509Certificates(options, &x509Certificates); + if (ret != RET_OK) { + sk_X509_pop_free(x509Certificates, X509_free); + SIGNATURE_TOOLS_LOGE("[SignBin] get X509 Certificates failed! errorCode:%d", ret); + return false; + } + if (!CheckCompatibleVersion()) { + sk_X509_pop_free(x509Certificates, X509_free); + SIGNATURE_TOOLS_LOGE("check Compatible Version failed!"); + return false; + } + + SignerConfig signerConfig; + if (!InitSigerConfig(signerConfig, x509Certificates, options)) { + SIGNATURE_TOOLS_LOGE("[SignBin] create Signer Configs failed"); + return false; + } + + bool signFlag = SignBin::Sign(signerConfig, signParams); + if (!signFlag) { + SIGNATURE_TOOLS_LOGE("sign bin internal failed"); + return false; + } + + SIGNATURE_TOOLS_LOGI("sign bin success"); + return true; +} + +bool SignProvider::AppendCodeSignBlock(SignerConfig* signerConfig, std::string outputFilePath, + const std::string& suffix, int64_t centralDirectoryOffset, ZipSigner& zip) +{ + if (signParams.at(ParamConstants::PARAM_SIGN_CODE) == CodeSigning::ENABLE_SIGN_CODE_VALUE) { + SIGNATURE_TOOLS_LOGI("start code signing."); + if (std::find(CodeSigning::SUPPORT_FILE_FORM.begin(), CodeSigning::SUPPORT_FILE_FORM.end(), + suffix) == CodeSigning::SUPPORT_FILE_FORM.end()) { + SIGNATURE_TOOLS_LOGI("no need to sign code for %s", suffix.c_str()); + return true; + } + // 4 means hap format occupy 4 byte storage location,2 means optional blocks reserve 2 storage location + int64_t codeSignOffset = centralDirectoryOffset + ((4 + 4 + 4) * (optionalBlocks.size() + 2 + 1)); + // create CodeSigning Object + CodeSigning codeSigning(signerConfig); + std::vector codeSignArray; + if (!codeSigning.GetCodeSignBlock(outputFilePath, codeSignOffset, suffix, profileContent, zip, + codeSignArray)) { + SIGNATURE_TOOLS_LOGE("Codesigning getCodeSignBlock Fail."); + return false; + } + SIGNATURE_TOOLS_LOGI("generate codeSignArray finished."); + std::unique_ptr result = + std::make_unique(codeSignArray.size() + + (FOUR_BYTE + FOUR_BYTE + FOUR_BYTE)); + result->PutInt32(HapUtils::HAP_CODE_SIGN_BLOCK_ID); + result->PutInt32(codeSignArray.size()); // length + result->PutInt32((int32_t)codeSignOffset); // offset + result->PutData(codeSignArray.data(), codeSignArray.size()); + + OptionalBlock tmp = {HapUtils::HAP_PROPERTY_BLOCK_ID, *result}; + optionalBlocks.insert(optionalBlocks.begin(), tmp); + } + 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("[SignHap] 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 (!HapUtils::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 inForm = options->GetString(Options::INFORM); + std::string profileFile = options->GetString(Options::PROFILE_FILE); + if (StringUtils::CaseCompare(inForm, ELF) && 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::DoAfterSign(bool isPathOverlap, std::string tmpOutputFile, std::string inputFilePath) +{ + if (isPathOverlap) { + remove(inputFilePath.c_str()); + if (rename(tmpOutputFile.c_str(), inputFilePath.c_str()) != 0) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, + "File name " + tmpOutputFile + " rename to " + inputFilePath + " failed!"); + return false; + } + } + return true; +} + +bool SignProvider::CopyFileAndAlignment(std::ifstream& input, std::ofstream& tmpOutput, int alignment, ZipSigner& zip) +{ + if (!zip.Init(input)) { + PrintErrorNumberMsg("ZIP_ERROR", ZIP_ERROR, "zip init failed"); + return false; + } + zip.Alignment(alignment); + zip.RemoveSignBlock(); + if (!zip.ToFile(input, tmpOutput)) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "zip write to file failed"); + return false; + } + 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_BASIC_COMPATIBLE_VERSION); + paramFileds.emplace_back(ParamConstants::PARAM_SIGN_CODE); + paramFileds.emplace_back(ParamConstants::PARAM_IN_FORM); + + 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] = "1"; + } + if (!CheckSignCode()) { + SIGNATURE_TOOLS_LOGE("signCode Parameter check error, signCode must is 0 or 1"); + return false; + } + if (!CheckSignatureAlg()) { + SIGNATURE_TOOLS_LOGE("signAlg Parameter is not support"); + return false; + } + CheckSignAlignment(); + return true; +} + +bool SignProvider::CheckSignCode() +{ + if (signParams.find(ParamConstants::PARAM_SIGN_CODE) == signParams.end()) { + signParams.insert(std::make_pair(ParamConstants::PARAM_SIGN_CODE, ParamConstants::ENABLE_SIGN_CODE)); + return true; + } + std::string codeSign = signParams[ParamConstants::PARAM_SIGN_CODE]; + if ((codeSign != ParamConstants::ENABLE_SIGN_CODE) && (codeSign != ParamConstants::DISABLE_SIGN_CODE)) { + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, + "signCode Parameter must 0 or 1, you put is " + codeSign); + return false; + } + 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 = signAlg.substr(0, 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)); + } +} + +bool SignProvider::CheckStringToint(const std::string& in, int& out) +{ + std::istringstream iss(in); + if ((iss >> out) && iss.eof()) { + return true; + } else { + SIGNATURE_TOOLS_LOGE("Invalid parameter: %s", in.c_str()); + return false; + } +} + +bool SignProvider::CheckCompatibleVersion() +{ + auto it = signParams.find(ParamConstants::PARAM_BASIC_COMPATIBLE_VERSION); + if (it == signParams.end()) { + signParams[ParamConstants::PARAM_BASIC_COMPATIBLE_VERSION] = "9"; + return true; + } + const std::string& compatibleApiVersionVal = it->second; + int compatibleApiVersion; + if (!CheckStringToint(compatibleApiVersionVal, compatibleApiVersion)) { + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, + "compatibleVersion Parameter is must integer"); + return false; + } + return true; +} + +bool SignProvider::OutputSignedFile(RandomAccessFile* outputHap, + long centralDirectoryOffset, + ByteBuffer& signingBlock, + ByteBufferDataSource* centralDirectory, + ByteBuffer& eocdBuffer) +{ + std::shared_ptr outputHapOut = + std::make_shared(outputHap, centralDirectoryOffset); + if (!outputHapOut->Write(signingBlock)) { + SIGNATURE_TOOLS_LOGE("output hap file write signingBlock failed"); + return false; + } + if (!outputHapOut->Write(centralDirectory->GetByteBuffer())) { + SIGNATURE_TOOLS_LOGE("output hap file write central directory failed"); + return false; + } + if (!outputHapOut->Write(eocdBuffer) != 0) { + SIGNATURE_TOOLS_LOGE("output hap file write eocd failed"); + return false; + } + return true; +} + +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 = (ParamConstants::DISABLE_SIGN_CODE == 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/hapsigntool_cpp/hap/sign/.gitignore b/hapsigntool_cpp/hap/sign/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..259148fa18f9fb7ef58563f4ff15fc7b172339fb --- /dev/null +++ b/hapsigntool_cpp/hap/sign/.gitignore @@ -0,0 +1,32 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/hapsigntool_cpp/hap/sign/include/bc_pkcs7_generator.h b/hapsigntool_cpp/hap/sign/include/bc_pkcs7_generator.h new file mode 100644 index 0000000000000000000000000000000000000000..cce86f75f99bc7ee5b0290e3ff4db01c72d92a95 --- /dev/null +++ b/hapsigntool_cpp/hap/sign/include/bc_pkcs7_generator.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024-2024 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; +private: + int PackagePKCS7(const std::string& content, 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/hapsigntool_cpp/hap/sign/include/pkcs7_generator.h b/hapsigntool_cpp/hap/sign/include/pkcs7_generator.h new file mode 100644 index 0000000000000000000000000000000000000000..7be632d42b6b8b40523e844bf0c7aeb35bc9f5ba --- /dev/null +++ b/hapsigntool_cpp/hap/sign/include/pkcs7_generator.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024-2024 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/hapsigntool_cpp/hap/sign/include/sign_bin.h b/hapsigntool_cpp/hap/sign/include/sign_bin.h new file mode 100644 index 0000000000000000000000000000000000000000..532986f6dfbc0d1a059cf89779b045243542844a --- /dev/null +++ b/hapsigntool_cpp/hap/sign/include/sign_bin.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024-2024 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_BIN_H +#define SIGNATRUETOOLS_SIGN_BIN_H + +#include "signer_config.h" + +namespace OHOS { +namespace SignatureTools { +class SignBin { +public: + static bool Sign(SignerConfig& signerConfig, const std::map& signParams); + static std::vector GenerateFileDigest(const std::string& outputFile, + const std::string& signAlg); + +private: + static bool WriteBlockDataToFile(const std::string& inputFile, const std::string& outputFile, + const std::string& profileFile, const std::string& profileSigned); + static bool WriteSignDataToOutputFile(SignerConfig& SignerConfig, const std::string& outputFile, + const std::string& signAlg); + static bool WriteSignHeadDataToOutputFile(const std::string& inputFile, const std::string& outputFile); + static bool CheckBinAndProfileLengthIsValid(int64_t binFileLen, int64_t profileDataLen); + static bool IsLongOverflowInteger(int64_t num); + static bool IsLongOverflowShort(int64_t num); + static bool WriteSignedBin(const std::string& inputFile, const std::string& proBlockByte, + const std::string& signBlockByte, const std::string& profileFile, + const std::string& outputFile); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif \ No newline at end of file diff --git a/hapsigntool_cpp/hap/sign/include/sign_elf.h b/hapsigntool_cpp/hap/sign/include/sign_elf.h new file mode 100644 index 0000000000000000000000000000000000000000..a554311d147c2f03eb5e48916d8bb1d9900c96ce --- /dev/null +++ b/hapsigntool_cpp/hap/sign/include/sign_elf.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024-2024 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 + +#include "signer_config.h" +#include "sign_block_data.h" +#include "hap_signer_block_utils.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 CODESIGN_OFF; + + static bool AlignFileBy4kBytes(std::string& inputFile, std::string& tmp); + static bool WriteBlockDataToFile(SignerConfig& signerConfig, + std::string inputFile, std::string outputFile, + std::string profileSigned, + std::map signParams); + static bool WriteSignedElf(std::string inputFile, + std::list& signBlockList, std::string outputFile); + static bool WriteSignBlockData(std::list& signBlockList, std::ofstream& fileOutputStream); + static bool GenerateSignBlockHead(std::list& signDataList); + static SignBlockData GenerateProfileSignByte(std::string profileFile, std::string profileSigned); + static bool GenerateCodeSignByte(SignerConfig& signerConfig, std::map signParams, + std::string inputFile, int blockNum, + long binFileLen, SignBlockData** codeSign); + static bool WriteSignHeadDataToOutputFile(std::string inputFile, std::string outputFile, int blockNum); + static bool IsLongOverflowInteger(int64_t num); + static bool IsLongOverflowShort(int64_t num); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif diff --git a/hapsigntool_cpp/hap/sign/include/sign_hap.h b/hapsigntool_cpp/hap/sign/include/sign_hap.h new file mode 100644 index 0000000000000000000000000000000000000000..40b9501c44397c54455f5c3a25d3212519a92f32 --- /dev/null +++ b/hapsigntool_cpp/hap/sign/include/sign_hap.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024-2024 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_HAP_H +#define SIGNATRUETOOLS_SIGH_HAP_H +#include +#include +#include +#include + +#include "hap_utils.h" +#include "hap_verify_result.h" +#include "signer_config.h" +#include "hap_signer_block_utils.h" +#include "securec.h" + +namespace OHOS { +namespace SignatureTools { +class SignHap { +public: + static bool Sign(DataSource* contents[], int32_t len, SignerConfig& config, + std::vector& optionalBlocks, ByteBuffer& result); + static bool ComputeDigests(const DigestParameter& digestParam, DataSource* contents[], int32_t len, + const std::vector& optionalBlocks, ByteBuffer& result); + +private: + static constexpr int INT_SIZE = 4; + static constexpr int CONTENT_VERSION = 2; + static constexpr int BLOCK_NUMBER = 1; + static constexpr int CONTENT_NUBER = 3; + static constexpr int STORED_ENTRY_SO_ALIGNMENT = 4096; + static constexpr int BUFFER_LENGTH = 4096; + static constexpr int BLOCK_COUNT = 4; + static constexpr int BLOCK_MAGIC = 16; + static constexpr int BLOCK_VERSION = 4; + static constexpr long INIT_OFFSET_LEN = 4L; + static constexpr int OPTIONAL_TYPE_SIZE = 4; + static constexpr int OPTIONAL_LENGTH_SIZE = 4; + static constexpr int OPTIONAL_OFFSET_SIZE = 4; + static void ExtractedResult(std::vector& optionalBlocks, ByteBuffer& result, + std::unordered_map& typeAndOffsetMap); + static bool GenerateHapSigningBlock(const std::string& hapSignatureSchemeBlock, + std::vector& optionalBlocks, + int compatibleVersion, ByteBuffer& result); + static void EncodeListOfPairsToByteArray(const DigestParameter& digestParam, + const std::vector>& contentDigests, + ByteBuffer& result); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_SIGH_HAP_H diff --git a/hapsigntool_cpp/hap/sign/src/bc_pkcs7_generator.cpp b/hapsigntool_cpp/hap/sign/src/bc_pkcs7_generator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ba729012e07ff902bed9578d85755f7a26c04806 --- /dev/null +++ b/hapsigntool_cpp/hap/sign/src/bc_pkcs7_generator.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024-2024 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 "signature_tools_log.h" +#include "pkcs7_data.h" +#include "signature_algorithm_helper.h" +#include "bc_signeddata_generator.h" +#include "signer_config.h" +#include "signature_tools_errno.h" +#include "bc_pkcs7_generator.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 = BCSignedDataGenerator::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, 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; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/hap/sign/src/sign_bin.cpp b/hapsigntool_cpp/hap/sign/src/sign_bin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c42f75f4316ff2f29f8c4c059c98b0ca5eff4024 --- /dev/null +++ b/hapsigntool_cpp/hap/sign/src/sign_bin.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2024-2024 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_bin.h" +#include "param_constants.h" +#include "file_utils.h" +#include "hw_block_head.h" +#include "signature_block_types.h" +#include "signature_block_tags.h" +#include "hash_utils.h" +#include "sign_content_info.h" +#include "hw_sign_head.h" +#include "bc_pkcs7_generator.h" +#include "params.h" + +namespace OHOS { +namespace SignatureTools { + +bool SignBin::Sign(SignerConfig& signerConfig, const std::map& signParams) +{ + /* 1. Make block head, write to output file. */ + std::string signCode = signParams.at(ParamConstants::PARAM_SIGN_CODE); + if (ParamConstants::ENABLE_SIGN_CODE == signCode) { + SIGNATURE_TOOLS_LOGW("can not sign bin with codesign.\n"); + } + std::string inputFile = signParams.at(ParamConstants::PARAM_BASIC_INPUT_FILE); + std::string outputFile = signParams.at(ParamConstants::PARAM_BASIC_OUTPUT_FILE); + std::string profileFile = signParams.at(ParamConstants::PARAM_BASIC_PROFILE); + std::string profileSigned = signParams.at(ParamConstants::PARAM_BASIC_PROFILE_SIGNED); + bool writeBlockOk = WriteBlockDataToFile(inputFile, outputFile, profileFile, profileSigned); + if (!writeBlockOk) { + SIGNATURE_TOOLS_LOGE("The block head data made failed."); + FileUtils::DelDir(outputFile); + return false; + } + /* 2. Make sign data, and append write to output file */ + std::string signAlg = signParams.at(ParamConstants::PARAM_BASIC_SIGANTURE_ALG); + bool writeSignDataOk = WriteSignDataToOutputFile(signerConfig, outputFile, signAlg); + if (!writeSignDataOk) { + SIGNATURE_TOOLS_LOGE("The sign data made failed."); + FileUtils::DelDir(outputFile); + return false; + } + /* 3. Make sign head data, and write to output file */ + bool writeSignHeadDataOk = WriteSignHeadDataToOutputFile(inputFile, outputFile); + if (!writeSignHeadDataOk) { + SIGNATURE_TOOLS_LOGE("The sign head data made failed."); + FileUtils::DelDir(outputFile); + return false; + } + return true; +} + +bool SignBin::WriteBlockDataToFile(const std::string& inputFile, const std::string& outputFile, + const std::string& profileFile, const std::string& profileSigned) +{ + int64_t binFileLen = FileUtils::GetFileLen(inputFile); + int64_t profileDataLen = FileUtils::GetFileLen(profileFile); + bool isValid = CheckBinAndProfileLengthIsValid(binFileLen, profileDataLen); + if (!isValid) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "file length is invalid, binFileLen: " + std::to_string(binFileLen) + + "lld, profileDataLen: " + std::to_string(profileDataLen) + "lld"); + return false; + } + int64_t offset = binFileLen + HwBlockHead::GetBlockLen() + HwBlockHead::GetBlockLen(); + bool isOver = IsLongOverflowInteger(offset); + if (isOver) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The profile block head offset is overflow interger range in sign bin, offset: " + + std::to_string(offset)); + return false; + } + char isSigned = SignatureBlockTypes::GetProfileBlockTypes(profileSigned); + std::string proBlockByte = + HwBlockHead::GetBlockHead(isSigned, SignatureBlockTags::DEFAULT, (short)profileDataLen, (int)offset); + offset += profileDataLen; + isOver = IsLongOverflowInteger(offset); + if (isOver) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "The profile block head offset is overflow interger range in sign bin, offset: " + + std::to_string(offset)); + return false; + } + std::string signBlockByte = HwBlockHead::GetBlockHead( + SignatureBlockTypes::SIGNATURE_BLOCK, SignatureBlockTags::DEFAULT, (short)0, (int)offset); + return WriteSignedBin(inputFile, proBlockByte, signBlockByte, profileFile, outputFile); +} + +std::vector SignBin::GenerateFileDigest(const std::string& outputFile, + const std::string& signAlg) +{ + SignatureAlgorithmHelper signatureAlgorithmClass; + bool getAlgOk = Params::GetSignatureAlgorithm(signAlg, signatureAlgorithmClass); + if (!getAlgOk) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "[SignHap] get Signature Algorithm failed."); + return std::vector(); + } + std::string alg = signatureAlgorithmClass.m_contentDigestAlgorithm.GetDigestAlgorithm(); + std::vector data = HashUtils::GetFileDigest(outputFile, alg); + if (data.empty()) { + SIGNATURE_TOOLS_LOGE("GetFileDigest failed."); + return std::vector(); + } + std::vector outputChunk; + SignContentInfo contentInfo; + contentInfo.AddContentHashData(0, SignatureBlockTags::HASH_ROOT_4K, HashUtils::GetHashAlgsId(alg), + data.size(), data); + return contentInfo.GetByteContent(); +} + +bool SignBin::WriteSignDataToOutputFile(SignerConfig& SignerConfig, const std::string& outputFile, + const std::string& signAlg) +{ + std::vector dig = GenerateFileDigest(outputFile, signAlg); + if (dig.empty()) { + SIGNATURE_TOOLS_LOGE("generateSignature verity digest is null."); + return false; + } + std::string retStr; + std::string signedData(dig.begin(), dig.end()); + std::unique_ptr generator = std::make_unique(); + if (generator->GenerateSignedData(signedData, &SignerConfig, retStr)) { + SIGNATURE_TOOLS_LOGE("failed to GenerateSignedData!"); + return false; + } + bool writeByteToOutFile = FileUtils::AppendWriteByteToFile(retStr, outputFile); + if (!writeByteToOutFile) { + SIGNATURE_TOOLS_LOGE("write signedData to outputFile failed!"); + return false; + } + return true; +} + +bool SignBin::WriteSignHeadDataToOutputFile(const std::string& inputFile, const std::string& outputFile) +{ + int64_t size = FileUtils::GetFileLen(outputFile) - FileUtils::GetFileLen(inputFile) + HwSignHead::SIGN_HEAD_LEN; + bool isOver = IsLongOverflowInteger(size); + if (isOver) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "File size is Overflow integer range, size: " + std::to_string(size)); + return false; + } + HwSignHead signHeadData; + std::vector signHeadByte = signHeadData.GetSignHead(size); + if (signHeadByte.empty()) { + SIGNATURE_TOOLS_LOGE("Failed to get sign head data!"); + return false; + } + bool writeByteToOutFile = + FileUtils::AppendWriteByteToFile(std::string(signHeadByte.begin(), signHeadByte.end()), outputFile); + if (!writeByteToOutFile) { + SIGNATURE_TOOLS_LOGE("Failed to WriteByteToOutFile!"); + return false; + } + return true; +} + +bool SignBin::CheckBinAndProfileLengthIsValid(int64_t binFileLen, int64_t profileDataLen) +{ + return binFileLen != -1 && profileDataLen != -1 && !IsLongOverflowShort(profileDataLen); +} + +bool SignBin::IsLongOverflowInteger(int64_t num) +{ + return (num - (num & 0xffffffffL)) != 0; +} + +bool SignBin::IsLongOverflowShort(int64_t num) +{ + return (num - (num & 0xffff)) != 0; +} + +bool SignBin::WriteSignedBin(const std::string& inputFile, const std::string& proBlockByte, + const std::string& signBlockByte, const std::string& profileFile, + const std::string& outputFile) +{ + // 1. write the input file to the output file. + bool writeInputOk = FileUtils::WriteInputToOutPut(inputFile, outputFile); + // 2. append write profile block head to the output file. + bool appendProfileHeadOk = FileUtils::AppendWriteByteToFile(proBlockByte, outputFile); + // 3. append write sign block head to the output file. + bool appendBlockHeadOk = FileUtils::AppendWriteByteToFile(signBlockByte, outputFile); + // 4. write profile src file to the output file. + bool appendProfileSrcOk = FileUtils::AppendWriteFileToFile(profileFile, outputFile); + if (!writeInputOk || !appendProfileHeadOk || !appendBlockHeadOk || !appendProfileSrcOk) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "Failed to write signed bin"); + return false; + } + return true; +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/hap/sign/src/sign_elf.cpp b/hapsigntool_cpp/hap/sign/src/sign_elf.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f66fc7ab58b41174a183ec9ffcde35eed950443 --- /dev/null +++ b/hapsigntool_cpp/hap/sign/src/sign_elf.cpp @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2024-2024 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 "sign_elf.h" +#include "string_utils.h" +#include "code_signing.h" +#include "param_constants.h" +#include "hw_block_head.h" +#include "hw_sign_head.h" +#include "signature_block_types.h" +#include "signature_block_tags.h" + +namespace OHOS { +namespace SignatureTools { + +int SignElf::blockNum = 0; +const std::string SignElf::CODESIGN_OFF = "0"; + +bool SignElf::Sign(SignerConfig& signerConfig, std::map& signParams) +{ + std::string inputFile = signParams.at(ParamConstants::PARAM_BASIC_INPUT_FILE); + std::string tmpFile; + bool checkAlignFileBy4kBytesFlag = AlignFileBy4kBytes(inputFile, tmpFile); + if (!checkAlignFileBy4kBytesFlag) { + SIGNATURE_TOOLS_LOGE("[SignElf] AlignFileBy4kBytes error"); + remove(tmpFile.c_str()); + return false; + } + std::string outputFile = signParams.at(ParamConstants::PARAM_BASIC_OUTPUT_FILE); + std::string profileSigned = signParams.at(ParamConstants::PARAM_BASIC_PROFILE_SIGNED); + bool checkWriteBlockDataToFileFlag = WriteBlockDataToFile(signerConfig, tmpFile, + outputFile, profileSigned, signParams); + if (!checkWriteBlockDataToFileFlag) { + SIGNATURE_TOOLS_LOGE("[SignElf] WriteBlockDataToFile error"); + remove(tmpFile.c_str()); + return false; + } + bool checkWriteSignHeadDataToOutputFileFlag = WriteSignHeadDataToOutputFile(tmpFile, outputFile, blockNum); + if (!checkWriteSignHeadDataToOutputFileFlag) { + SIGNATURE_TOOLS_LOGE("[SignElf] WriteSignHeadDataToOutputFile error"); + remove(tmpFile.c_str()); + return false; + } + return (remove(tmpFile.c_str()) == 0); + ; +} + +bool SignElf::AlignFileBy4kBytes(std::string& inputFile, std::string& tmpFile) +{ + auto now = std::chrono::high_resolution_clock::now(); + auto duration = now.time_since_epoch(); + auto timeStamp = std::chrono::duration_cast(duration).count(); + tmpFile = "tmpFile" + std::to_string(timeStamp); + std::ofstream output(tmpFile); + bool checkSpaceFlag = FileUtils::IsSpaceEnough(std::string("./"), FileUtils::GetFileLen(inputFile)); + if (!checkSpaceFlag) { + char currentPath[FILE_PATH_LENGTH] = { 0 }; + getcwd(currentPath, FILE_PATH_LENGTH); + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "[SignElf] The available space of the current directory: " + + std::string(currentPath) + " is insufficient. Please check"); + return false; + } + bool checkOutputFlag = output.is_open(); + if (!checkOutputFlag) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "[SignElf] open file: " + tmpFile + "failed"); + return false; + } + std::ifstream input(inputFile); + bool checkInputFlag = input.is_open(); + if (!checkInputFlag) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "[SignElf] open file: " + inputFile + "failed"); + return false; + } + char buffer[FILE_BUFFER_BLOCK]; + std::streamsize bytesRead; + int64_t outputLength = 0; + while ((bytesRead = input.read(buffer, sizeof(buffer)).gcount()) > 0) { + output.write(buffer, bytesRead); + if (!output) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "[SignElf] write data to " + tmpFile + "failed"); + return false; + } + outputLength += bytesRead; + } + int64_t addLength = PAGE_SIZE - (outputLength % PAGE_SIZE); + std::vector bytes(addLength, 0); + output.write(bytes.data(), addLength); + return true; +} + +bool SignElf::WriteBlockDataToFile(SignerConfig& signerConfig, + std::string inputFile, std::string outputFile, std::string profileSigned, + std::map signParams) +{ + std::string proFile; + if (signParams.find(ParamConstants::PARAM_BASIC_PROFILE) != signParams.end()) { + proFile = signParams.at(ParamConstants::PARAM_BASIC_PROFILE); + } + std::list signDataList; + int64_t binFileLen = FileUtils::GetFileLen(inputFile); + bool checkFlag = binFileLen < 0 || IsLongOverflowInteger(binFileLen); + if (checkFlag) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "[SignElf] The length exceeds the maximum limit."); + return false; + } + bool checkIsEmptyFlag = StringUtils::IsEmpty(proFile); + if (!checkIsEmptyFlag) { + signDataList.push_front(GenerateProfileSignByte(proFile, profileSigned)); + } + blockNum = signDataList.size() + 1; + SignBlockData* codeSign = nullptr; + bool checkGenerateCodeSignByteFlag = !GenerateCodeSignByte(signerConfig, signParams, inputFile, blockNum, + binFileLen, &codeSign) || !codeSign; + if (checkGenerateCodeSignByteFlag) { + SIGNATURE_TOOLS_LOGE("[SignElf] generate code sign byte error."); + if (codeSign) { + delete codeSign; + } + return false; + } + signDataList.push_front(*codeSign); + blockNum = signDataList.size(); + bool checkGenerateSignBlockHeadFlag = GenerateSignBlockHead(signDataList); + if (!checkGenerateSignBlockHeadFlag) { + SIGNATURE_TOOLS_LOGE("[SignElf] generate sign block head error."); + delete codeSign; + return false; + } + delete codeSign; + return WriteSignedElf(inputFile, signDataList, outputFile); +} + +bool SignElf::WriteSignedElf(std::string inputFile, std::list& signBlockList, std::string outputFile) +{ + std::ifstream fileInputStream(inputFile, std::ios::binary); + std::ofstream fileOutputStream(outputFile, std::ios::binary); + bool checkFlag = !fileInputStream.is_open(); + if (checkFlag) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "[SignElf] open file: " + inputFile + "failed"); + return false; + } + checkFlag = !fileOutputStream.is_open(); + if (checkFlag) { + fileInputStream.close(); + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "[SignElf] open file: " + outputFile + "failed"); + return false; + } + char buffer[FILE_BUFFER_BLOCK]; + while (!fileInputStream.eof()) { + fileInputStream.read(buffer, sizeof(buffer)); + fileOutputStream.write(buffer, fileInputStream.gcount()); + } + bool writeFlag = WriteSignBlockData(signBlockList, fileOutputStream); + if (!writeFlag) { + SIGNATURE_TOOLS_LOGE("[SignElf] write signBlockList to file error"); + fileInputStream.close(); + fileOutputStream.close(); + return false; + } + fileInputStream.close(); + fileOutputStream.close(); + return true; +} + +bool SignElf::WriteSignBlockData(std::list& signBlockList, std::ofstream& fileOutputStream) +{ + for (auto& signBlockData : signBlockList) { + bool checkWriteByteToOutFileFlag = FileUtils::WriteByteToOutFile(signBlockData.GetBlockHead(), + fileOutputStream); + if (!checkWriteByteToOutFileFlag) { + SIGNATURE_TOOLS_LOGE("[SignElf] write data to file error"); + return false; + } + } + for (auto& signBlockData : signBlockList) { + bool isSuccess; + bool checkFlag = signBlockData.GetByte(); + if (checkFlag) { + isSuccess = FileUtils::WriteByteToOutFile(signBlockData.GetSignData(), fileOutputStream); + } else { + std::ifstream InputSignFileStream(signBlockData.GetSignFile(), std::ios::binary); + bool checkFileFlag = !InputSignFileStream.is_open(); + if (checkFileFlag) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, + "[SignElf] open file: " + signBlockData.GetSignFile() + "failed"); + return false; + } + int result = FileUtils::WriteInputToOutPut(InputSignFileStream, fileOutputStream, + (long)signBlockData.GetLen()); + isSuccess = (result == 0 ? true : false); + } + if (!isSuccess) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "write data to file error"); + return false; + } + } + return true; +} + +bool SignElf::GenerateSignBlockHead(std::list& signDataList) +{ + int64_t offset = HwBlockHead::GetElfBlockLen() * signDataList.size(); + for (std::list::iterator it = signDataList.begin(); it != signDataList.end(); ++it) { + std::vector tmp = HwBlockHead::GetBlockHeadLittleEndian(it->GetType(), + SignatureBlockTags::DEFAULT, + it->GetLen(), offset); + it->SetBlockHead(tmp); + offset += it->GetLen(); + bool checkIsLongOverflowIntegerFlag = IsLongOverflowInteger(offset); + if (checkIsLongOverflowIntegerFlag) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "[SignElf] The length exceeds the maximum limit."); + return false; + } + } + return true; +} + +SignBlockData SignElf::GenerateProfileSignByte(std::string profileFile, std::string profileSigned) +{ + int64_t profileDataLen = FileUtils::GetFileLen(profileFile); + if (profileDataLen < 0 || IsLongOverflowShort(profileDataLen)) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "[SignElf] The length exceeds the maximum limit."); + } + char isSigned = SignatureBlockTypes::GetProfileBlockTypes(profileSigned); + return SignBlockData(profileFile, isSigned); +} + +bool SignElf::GenerateCodeSignByte(SignerConfig& signerConfig, std::map signParams, + std::string inputFile, int blockNum, long binFileLen, SignBlockData** codeSign) +{ + if (signParams.at(ParamConstants::PARAM_SIGN_CODE) == CODESIGN_OFF) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "[SignElf] check pamams signCode = 0 error."); + return false; + } + CodeSigning codeSigning(&signerConfig); + long offset = binFileLen + (long)HwBlockHead::GetElfBlockLen() * blockNum; + std::string profileContent; + if (signParams.find(ParamConstants::PARAM_PROFILE_JSON_CONTENT) != signParams.end()) { + profileContent = signParams.at(ParamConstants::PARAM_PROFILE_JSON_CONTENT); + } + std::vector codesignData; + bool checkGetElfCodeSignBlockFlag = codeSigning.GetElfCodeSignBlock(inputFile, offset, + signParams.at(ParamConstants::PARAM_IN_FORM), + profileContent, codesignData); + if (!checkGetElfCodeSignBlockFlag) { + SIGNATURE_TOOLS_LOGE("[SignElf] get elf code sign block error."); + return false; + } + *codeSign = new SignBlockData(codesignData, CODESIGN_BLOCK_TYPE); + return true; +} + +bool SignElf::WriteSignHeadDataToOutputFile(std::string inputFile, std::string outputFile, int blockNum) +{ + int64_t size = FileUtils::GetFileLen(outputFile) - FileUtils::GetFileLen(inputFile); + if (IsLongOverflowInteger(size)) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "[SignElf] The length exceeds the maximum limit."); + return false; + } + HwSignHead signHeadData; + std::vector signHeadByte = signHeadData.GetSignHeadLittleEndian((int)size, blockNum); + std::ofstream fileOutputStream(outputFile, std::ios::app | std::ios::binary); + return FileUtils::WriteByteToOutFile(signHeadByte, fileOutputStream); +} + +bool SignElf::IsLongOverflowInteger(int64_t num) +{ + return (num - (num & 0xffffffffL)) != 0; +} + +bool SignElf::IsLongOverflowShort(int64_t num) +{ + return (num - (num & 0xffffL)) != 0; +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/hap/sign/src/sign_hap.cpp b/hapsigntool_cpp/hap/sign/src/sign_hap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bef94866200e38009ec71d288541bb32e71ec0b4 --- /dev/null +++ b/hapsigntool_cpp/hap/sign/src/sign_hap.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2024-2024 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_algorithm_helper.h" +#include "bc_pkcs7_generator.h" +#include "sign_hap.h" + +namespace OHOS { +namespace SignatureTools { +bool SignHap::Sign(DataSource* contents[], int32_t len, SignerConfig& config, + std::vector& optionalBlocks, ByteBuffer& result) +{ + if (len != CONTENT_NUBER) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, + "zip contents len must is 3, now is " + std::to_string(len)); + return false; + } + std::vector algoClass = config.GetSignatureAlgorithms(); + if (algoClass.empty()) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "Signature Algorithms is empty"); + return false; + } + SignatureAlgorithm algo = static_cast(algoClass[0].m_id); + SIGNATURE_TOOLS_LOGI("[SignHap] Signature Algorithm is %d", algo); + int32_t nId = VerifyHapOpensslUtils::GetDigestAlgorithmId(algo); + DigestParameter digestParam = HapSignerBlockUtils::GetDigestParameter(nId); + ByteBuffer digContext; + std::vector> nidAndcontentDigestsVec; + // 1:Summarize corresponding content and optionalBlock + if (!ComputeDigests(digestParam, contents, CONTENT_NUBER, optionalBlocks, digContext)) { + SIGNATURE_TOOLS_LOGE("[SignHap] compute Digests failed"); + return false; + } + SIGNATURE_TOOLS_LOGI("[SignHap] ComputeDigests %d", digContext.GetCapacity()); + // 2:Encoding Summary Information + ByteBuffer digMessage; + std::pair nidAndcontentDigests = std::make_pair(algo, digContext); + nidAndcontentDigestsVec.push_back(nidAndcontentDigests); + EncodeListOfPairsToByteArray(digestParam, nidAndcontentDigestsVec, digMessage); + + SIGNATURE_TOOLS_LOGI("[SignHap] EncodeListOfPairsToByteArray %d", digMessage.GetCapacity()); + // 3:Encrypt the encoded summary information. + std::shared_ptr pkcs7Generator = std::make_shared(); + std::string digMessageData(digMessage.GetBufferPtr(), digMessage.GetCapacity()); + std::string ret; + if (pkcs7Generator->GenerateSignedData(digMessageData, &config, ret) != 0) { + SIGNATURE_TOOLS_LOGE("[SignHap] Generate Signed Data failed"); + return false; + } + SIGNATURE_TOOLS_LOGI("[SignHap] GenerateSignedData %lu", static_cast(ret.size())); + bool checkGenerateHapSigningBlockFlag = GenerateHapSigningBlock(ret, optionalBlocks, + config.GetCompatibleVersion(), result); + if (!checkGenerateHapSigningBlockFlag) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "Generate Hap Signing Block failed"); + return false; + } + SIGNATURE_TOOLS_LOGI("[SignHap] GenerateHapSigningBlock %d", result.GetCapacity()); + return true; +} + +bool SignHap::ComputeDigests(const DigestParameter& digestParam, DataSource* contents[], int32_t len, + const std::vector& optionalBlocks, ByteBuffer& result) +{ + ByteBuffer chunkDigest; + bool ret = HapSignerBlockUtils::ComputeDigestsForEachChunk(digestParam, contents, len, chunkDigest); + if (!ret) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "Compute Content Digests failed"); + return false; + } + bool checkComputeDigestsWithOptionalBlockFlag = + HapSignerBlockUtils::ComputeDigestsWithOptionalBlock(digestParam, optionalBlocks, chunkDigest, result); + if (!checkComputeDigestsWithOptionalBlockFlag) { + PrintErrorNumberMsg("SIGN_ERROR", SIGN_ERROR, "Compute Final Digests failed"); + return false; + } + return true; +} + +void SignHap::EncodeListOfPairsToByteArray(const DigestParameter& digestParam, + const std::vector>&nidAndcontentDigests, ByteBuffer& result) +{ + int encodeSize = 0; + encodeSize += INT_SIZE + INT_SIZE; + for (const auto& pair : nidAndcontentDigests) { + encodeSize += INT_SIZE + INT_SIZE + INT_SIZE + pair.second.GetCapacity(); + } + result.SetCapacity(encodeSize); + result.PutInt32(CONTENT_VERSION); // version + result.PutInt32(BLOCK_NUMBER); // block number + for (const auto& pair : nidAndcontentDigests) { + auto second = pair.second; + result.PutInt32(INT_SIZE + INT_SIZE + second.GetCapacity()); + result.PutInt32(pair.first); + result.PutInt32(second.GetCapacity()); + result.Put(second); + } + return; +} + +bool SignHap::GenerateHapSigningBlock(const std::string& hapSignatureSchemeBlock, + std::vector& optionalBlocks, + int compatibleVersion, ByteBuffer& result) +{ + // FORMAT: + // Proof-of-Rotation pairs(optional): + // uint32:type + // uint32:length + // uint32:offset + // Property pairs(optional): + // uint32:type + // uint32:length + // uint32:offset + // Profile capability pairs(optional): + // uint32:type + // uint32:length + // uint32:offset + // length bytes : app signing pairs + // uint32:type + // uint32:length + // uint32:offset + // repeated ID-value pairs(reserved extensions): + // length bytes : Proof-of-Rotation values + // length bytes : property values + // length bytes : profile capability values + // length bytes : signature schema values + // uint64: size + // uint128: magic + // uint32: version + long optionalBlockSize = 0L; + for (const auto& elem : optionalBlocks) optionalBlockSize += elem.optionalBlockValue.GetCapacity(); + long resultSize = ((OPTIONAL_TYPE_SIZE + OPTIONAL_LENGTH_SIZE + OPTIONAL_OFFSET_SIZE) * + (optionalBlocks.size() + 1)) + + optionalBlockSize + + hapSignatureSchemeBlock.size() + + BLOCK_COUNT + HapUtils::BLOCK_SIZE + BLOCK_MAGIC + BLOCK_VERSION; + if (resultSize > INT_MAX) { + SIGNATURE_TOOLS_LOGE("Illegal Argument. HapSigningBlock out of range: %ld", resultSize); + return false; + } + result.SetCapacity((int)resultSize); + std::unordered_map typeAndOffsetMap; + int currentOffset = ((OPTIONAL_TYPE_SIZE + OPTIONAL_LENGTH_SIZE + + OPTIONAL_OFFSET_SIZE) * (optionalBlocks.size() + 1)); + int currentOffsetInBlockValue = 0; + int blockValueSizes = (int)(optionalBlockSize + hapSignatureSchemeBlock.size()); + std::string blockValues(blockValueSizes, 0); + for (const auto& elem : optionalBlocks) { + if (memcpy_s(blockValues.data() + currentOffsetInBlockValue, blockValueSizes, + elem.optionalBlockValue.GetBufferPtr(), + elem.optionalBlockValue.GetCapacity()) != 0) { + SIGNATURE_TOOLS_LOGE("GenerateHapSigningBlock memcpy_s failed\n"); + return false; + } + typeAndOffsetMap.insert({ elem.optionalType, currentOffset }); + currentOffset += elem.optionalBlockValue.GetCapacity(); + currentOffsetInBlockValue += elem.optionalBlockValue.GetCapacity(); + } + if (memcpy_s(blockValues.data() + currentOffsetInBlockValue, blockValueSizes, hapSignatureSchemeBlock.data(), + hapSignatureSchemeBlock.size()) != 0) { + SIGNATURE_TOOLS_LOGE("GenerateHapSigningBlock memcpy_s failed\n"); + return false; + } + typeAndOffsetMap.insert({ HapUtils::HAP_SIGNATURE_SCHEME_V1_BLOCK_ID, currentOffset }); + ExtractedResult(optionalBlocks, result, typeAndOffsetMap); + result.PutInt32(HapUtils::HAP_SIGNATURE_SCHEME_V1_BLOCK_ID); // type + result.PutInt32(hapSignatureSchemeBlock.size()); // length + int offset = typeAndOffsetMap.at(HapUtils::HAP_SIGNATURE_SCHEME_V1_BLOCK_ID); + result.PutInt32(offset); // offset + result.PutData(blockValues.c_str(), blockValueSizes); + result.PutInt32(optionalBlocks.size() + 1); // Signing block count + result.PutInt64(resultSize); // length of hap signing block + std::vector signingBlockMagic = HapUtils::GetHapSigningBlockMagic(compatibleVersion); + result.PutData((const char*)signingBlockMagic.data(), signingBlockMagic.size()); // magic + result.PutInt32(HapUtils::GetHapSigningBlockVersion(compatibleVersion)); // version + return true; +} + +void SignHap::ExtractedResult(std::vector& optionalBlocks, ByteBuffer& result, + std::unordered_map& typeAndOffsetMap) +{ + int offset; + for (const auto& elem : optionalBlocks) { + result.PutInt32(elem.optionalType); // type + result.PutInt32(elem.optionalBlockValue.GetCapacity()); // length + offset = typeAndOffsetMap.at(elem.optionalType); + result.PutInt32(offset); // offset + } +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/hap/signature_tools_hap.gni b/hapsigntool_cpp/hap/signature_tools_hap.gni new file mode 100644 index 0000000000000000000000000000000000000000..b68777771505afb9111dc5d029eee478852323b2 --- /dev/null +++ b/hapsigntool_cpp/hap/signature_tools_hap.gni @@ -0,0 +1,50 @@ +# Copyright (c) 2024 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}/verify/src/hap_verify_result.cpp", + "${signature_tools_hap}/verify/src/verify_hap.cpp", + "${signature_tools_hap}/verify/src/verify_bin.cpp", + "${signature_tools_hap}/verify/src/verify_elf.cpp", + "${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}/entity/src/hw_block_data.cpp", + "${signature_tools_hap}/entity/src/hw_block_head.cpp", + "${signature_tools_hap}/entity/src/hw_sign_head.cpp", + "${signature_tools_hap}/entity/src/sign_block_info.cpp", + "${signature_tools_hap}/entity/src/sign_content_info.cpp", + "${signature_tools_hap}/entity/src/sign_block_data.cpp", + "${signature_tools_hap}/entity/src/signature_block_tags.cpp", + "${signature_tools_hap}/entity/src/signature_block_types.cpp", + "${signature_tools_hap}/entity/src/signing_block.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_hap.cpp", + "${signature_tools_hap}/sign/src/sign_bin.cpp", + "${signature_tools_hap}/sign/src/sign_elf.cpp", + "${signature_tools_hap}/utils/src/hap_utils.cpp", + "${signature_tools_hap}/sign/src/bc_pkcs7_generator.cpp", +] diff --git a/hapsigntool_cpp/hap/utils/.gitignore b/hapsigntool_cpp/hap/utils/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..259148fa18f9fb7ef58563f4ff15fc7b172339fb --- /dev/null +++ b/hapsigntool_cpp/hap/utils/.gitignore @@ -0,0 +1,32 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/hapsigntool_cpp/hap/utils/include/hap_utils.h b/hapsigntool_cpp/hap/utils/include/hap_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..deeadb956d14fe4036822f9d97b97a2aeac4d2bd --- /dev/null +++ b/hapsigntool_cpp/hap/utils/include/hap_utils.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024-2024 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 "signing_block.h" +#include "zip_data_input.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { +class HapUtils { +public: + class HapSignBlockInfo { + public: + virtual ~HapSignBlockInfo() + { + } + HapSignBlockInfo(int64_t offset, int version, ByteBuffer contentByteBuffer); + + virtual int GetVersion(); + virtual ByteBuffer GetContent(); + virtual int64_t GetOffset(); + + private: + const int64_t offset; + const int version; + ByteBuffer const content; + }; + +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; + +public: + static std::string GetAppIdentifier(const std::string& profileContent); + static std::pair ParseAppIdentifier(const std::string& profileContent); + static std::vector GetHapSigningBlockMagic(int compatibleVersion); + static int GetHapSigningBlockVersion(int compatibleVersion); + static bool ReadFileToByteBuffer(const std::string& file, ByteBuffer& buffer); + +private: + static const int32_t MAX_APP_ID_LEN = 32; + static const std::string HAP_DEBUG_OWNER_ID; + static std::set HAP_SIGNATURE_OPTIONAL_BLOCK_IDS; + static constexpr int MIN_COMPATIBLE_VERSION_FOR_SCHEMA_V3 = 8; + static const std::vector HAP_SIGNING_BLOCK_MAGIC_V2; + static const std::vector HAP_SIGNING_BLOCK_MAGIC_V3; + static constexpr int8_t ZIP_FIRST_LEVEL_CHUNK_PREFIX = 0x5a; + static const int8_t ZIP_SECOND_LEVEL_CHUNK_PREFIX = static_cast(0xa5); + static const int DIGEST_PRIFIX_LENGTH = 5; + static constexpr int BUFFER_LENGTH = 4096; + static const std::string HEX_CHAR_ARRAY; + + class StaticConstructor { + public: + StaticConstructor(); + }; + + static HapUtils::StaticConstructor staticConstructor; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif diff --git a/hapsigntool_cpp/hap/utils/src/hap_utils.cpp b/hapsigntool_cpp/hap/utils/src/hap_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b1f40df1a65421611c73a1ed013a734d75f6deaa --- /dev/null +++ b/hapsigntool_cpp/hap/utils/src/hap_utils.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2024-2024 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 "profile_verify.h" +#include "hap_utils.h" + +namespace OHOS { +namespace SignatureTools { + +const std::vector HapUtils::HAP_SIGNING_BLOCK_MAGIC_V2 = + std::vector{ 0x48, 0x41, 0x50, 0x20, 0x53, 0x69, 0x67, 0x20, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x34, 0x32 }; +const std::vector HapUtils::HAP_SIGNING_BLOCK_MAGIC_V3 = + std::vector{ 0x3c, 0x68, 0x61, 0x70, 0x20, 0x73, 0x69, 0x67, 0x6e, + 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3e }; +const std::string HapUtils::HEX_CHAR_ARRAY = "0123456789ABCDEF"; +const std::string HapUtils::HAP_DEBUG_OWNER_ID = "DEBUG_LIB_ID"; +std::set HapUtils::HAP_SIGNATURE_OPTIONAL_BLOCK_IDS; + +HapUtils::StaticConstructor::StaticConstructor() +{ + HAP_SIGNATURE_OPTIONAL_BLOCK_IDS.insert(HAP_PROOF_OF_ROTATION_BLOCK_ID); + HAP_SIGNATURE_OPTIONAL_BLOCK_IDS.insert(HAP_PROFILE_BLOCK_ID); + HAP_SIGNATURE_OPTIONAL_BLOCK_IDS.insert(HAP_PROPERTY_BLOCK_ID); +} + +HapUtils::StaticConstructor HapUtils::staticConstructor; + +std::string HapUtils::GetAppIdentifier(const std::string& profileContent) +{ + std::pair resultPair = ParseAppIdentifier(profileContent); + + std::string ownerID = resultPair.first; + std::string profileType = resultPair.second; + + if (profileType == "debug") { + return HAP_DEBUG_OWNER_ID; + } else if (profileType == "release") { + return ownerID; + } else { + return ""; + } +} + +std::pair HapUtils::ParseAppIdentifier(const std::string& profileContent) +{ + std::string ownerID; + std::string profileType; + + ProfileInfo provisionInfo; + ParseProfile(profileContent, provisionInfo); + + if (DEBUG == provisionInfo.type) { + profileType = "debug"; + } else { + profileType = "release"; + } + + BundleInfo bundleInfo = provisionInfo.bundleInfo; + + if (!bundleInfo.appIdentifier.empty()) { + ownerID = bundleInfo.appIdentifier; + } + + return std::pair(ownerID, profileType); +} + +std::vector HapUtils::GetHapSigningBlockMagic(int compatibleVersion) +{ + if (compatibleVersion >= MIN_COMPATIBLE_VERSION_FOR_SCHEMA_V3) { + return HAP_SIGNING_BLOCK_MAGIC_V3; + } + return HAP_SIGNING_BLOCK_MAGIC_V2; +} + +int HapUtils::GetHapSigningBlockVersion(int compatibleVersion) +{ + if (compatibleVersion >= MIN_COMPATIBLE_VERSION_FOR_SCHEMA_V3) { + return HAP_SIGN_SCHEME_V3_BLOCK_VERSION; + } + return HAP_SIGN_SCHEME_V2_BLOCK_VERSION; +} + +bool HapUtils::ReadFileToByteBuffer(const std::string& file, ByteBuffer& buffer) +{ + std::string ret; + if (FileUtils::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; +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/hap/verify/.gitignore b/hapsigntool_cpp/hap/verify/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..259148fa18f9fb7ef58563f4ff15fc7b172339fb --- /dev/null +++ b/hapsigntool_cpp/hap/verify/.gitignore @@ -0,0 +1,32 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/hapsigntool_cpp/hap/verify/include/hap_verify_result.h b/hapsigntool_cpp/hap/verify/include/hap_verify_result.h new file mode 100644 index 0000000000000000000000000000000000000000..ba3c9bdeaa882744f79c71d6e2ea1cbd98292e44 --- /dev/null +++ b/hapsigntool_cpp/hap/verify/include/hap_verify_result.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2024-2024 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_RESULT_H +#define SIGNATRUETOOLS_VERIFY_RESULT_H +#include +#include + +#include "export_define.h" +#include "byte_buffer.h" +#include "profile_info.h" + +namespace OHOS { +namespace SignatureTools { +enum class DevMode { + DEFAULT = 0, + DEV, + NON_DEV, +}; + +enum HapVerifyResultCode { + VERIFY_SUCCESS = 0, + FILE_PATH_INVALID = -1, + OPEN_FILE_ERROR = -2, + SIGNATURE_NOT_FOUND = -3, + VERIFY_APP_PKCS7_FAIL = -4, + PROFILE_PARSE_FAIL = -5, + APP_SOURCE_NOT_TRUSTED = -6, + GET_DIGEST_FAIL = -7, + VERIFY_INTEGRITY_FAIL = -8, + FILE_SIZE_TOO_LARGE = -9, + GET_PUBLICKEY_FAIL = -10, + GET_SIGNATURE_FAIL = -11, + NO_PROFILE_BLOCK_FAIL = -12, + VERIFY_SIGNATURE_FAIL = -13, + VERIFY_SOURCE_INIT_FAIL = -14, + OUT_PUT_FILE_FAIL = -15, + VERIFY_CODE_SIGN_FAIL = -16, +}; + +enum GetOptionalBlockResultCode { + GET_SUCCESS = 0, + NO_THIS_BLOCK_IN_PACKAGE = 1, +}; + +struct OptionalBlock { + int32_t optionalType = 0; + ByteBuffer optionalBlockValue; +}; + +class HapVerifyResult { +public: + DLL_EXPORT HapVerifyResult(); + DLL_EXPORT ~HapVerifyResult(); + DLL_EXPORT int32_t GetVersion() const; + DLL_EXPORT void SetVersion(int32_t signatureVersion); + DLL_EXPORT void SetPkcs7SignBlock(const ByteBuffer& pkcs7); + DLL_EXPORT void SetPkcs7ProfileBlock(const ByteBuffer& pkcs7); + DLL_EXPORT void SetOptionalBlocks(const std::vector& option); + DLL_EXPORT void SetProvisionInfo(const ProfileInfo& info); + DLL_EXPORT int32_t GetProperty(std::string& property) const; + DLL_EXPORT ProfileInfo GetProvisionInfo() const; + DLL_EXPORT std::vector GetPublicKey() const; + DLL_EXPORT std::vector GetSignature() const; + DLL_EXPORT std::vector GetProfile() const; + DLL_EXPORT void SetProfile(std::vector profile); + void SetPublicKey(const std::vector& inputPubkeys); + void SetSignature(const std::vector& inputSignatures); + DLL_EXPORT int32_t GetBlockFromOptionalBlocks(int32_t blockType, std::string& block) const; + +private: + int32_t version = 0; + std::vector publicKeys; + std::vector signatures; + ByteBuffer pkcs7SignBlock; + ByteBuffer pkcs7ProfileBlock; + std::vector optionalBlocks; + ProfileInfo provisionInfo; + std::vector profile; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_VERIFY_RESULT_H diff --git a/hapsigntool_cpp/hap/verify/include/matching_result.h b/hapsigntool_cpp/hap/verify/include/matching_result.h new file mode 100644 index 0000000000000000000000000000000000000000..9f56b1cfe4d49f8dc76379b1aa2a1fcbb3ae38b2 --- /dev/null +++ b/hapsigntool_cpp/hap/verify/include/matching_result.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024-2024 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 TrustedSources { + OTHER_TRUSTED_SOURCE = 0, + APP_GALLARY, + APP_SYSTEM, + APP_THIRD_PARTY_PRELOAD, +}; +enum MatchingStates { + DO_NOT_MATCH = 0, + MATCH_WITH_SIGN, + MATCH_WITH_PROFILE, + MATCH_WITH_PROFILE_DEBUG, + MATCH_WITH_TICKET, +}; +struct MatchingResult { + MatchingStates matchState; + TrustedSources source; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // HAP_MATCHING_RESULT_H diff --git a/hapsigntool_cpp/hap/verify/include/verify_bin.h b/hapsigntool_cpp/hap/verify/include/verify_bin.h new file mode 100644 index 0000000000000000000000000000000000000000..41948878af36485ef20bbc9eb1408d6f7d259baf --- /dev/null +++ b/hapsigntool_cpp/hap/verify/include/verify_bin.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024-2024 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_BIN_H +#define SIGNATRUETOOLS_VERIFY_BIN_H + +#include +#include + +#include "verify_elf.h" + +namespace OHOS { +namespace SignatureTools { +class VerifyBin { +public: + bool Verify(Options* options); + +private: + bool VerifyBinFile(const std::string& binFile, HapVerifyResult& verifyResult, + Options* options, Pkcs7Context& pkcs7Context); + bool VerifyBinDigest(SignBlockInfo& signBlockInfo); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif \ No newline at end of file diff --git a/hapsigntool_cpp/hap/verify/include/verify_elf.h b/hapsigntool_cpp/hap/verify/include/verify_elf.h new file mode 100644 index 0000000000000000000000000000000000000000..6045a890f14856550987ec3b695e928f8dcd0ca1 --- /dev/null +++ b/hapsigntool_cpp/hap/verify/include/verify_elf.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024-2024 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_ELF_H +#define SIGNATRUETOOLS_VERIFY_ELF_H + +#include +#include + +#include "options.h" +#include "hap_verify_result.h" +#include "hw_block_data.h" +#include "signing_block.h" +#include "pkcs7_context.h" +#include "sign_block_info.h" + +namespace OHOS { +namespace SignatureTools { +class VerifyElf { +public: + static const int8_t SIGNATURE_BLOCK; + static const int8_t PROFILE_NOSIGNED_BLOCK; + static const int8_t PROFILE_SIGNED_BLOCK; + static const int8_t KEY_ROTATION_BLOCK; + static const int8_t CODESIGNING_BLOCK_TYPE; + +public: + bool Verify(Options* options); + static bool CheckParams(Options* options); + static bool CheckSignFile(const std::string& signedFile); + static bool GetSignBlockData(std::vector& bytes, HwBlockData& hwBlockData, + const std::string fileType); + static bool GetSignBlockInfo(const std::string& file, SignBlockInfo& signBlockInfo, + const std::string fileType); + static bool GetFileDigest(std::vector& fileBytes, std::vector& signatrue, + SignBlockInfo& signBlockInfo); + static bool GetRawContent(std::vector& contentVec, std::string& rawContent); + static bool VerifyP7b(std::unordered_map& signBlockMap, Options* options, + Pkcs7Context& pkcs7Context, HapVerifyResult& verifyResult, std::string& profileJson); + +private: + bool VerifyElfFile(const std::string& elfFile, HapVerifyResult& verifyResult, + Options* options, Pkcs7Context& pkcs7Context); + static bool CheckMagicAndVersion(std::vector& bytes, int64_t& offset, + const std::string fileType); + static void GetElfSignBlock(std::vector& bytes, HwBlockData& hwBlockData, + std::unordered_map& signBlockMap); + static void GetBinSignBlock(std::vector& bytes, HwBlockData& hwBlockData, + std::unordered_map& signBlockMap); + static bool GenerateFileDigest(std::vector& fileBytes, SignBlockInfo& signBlockInfo); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif \ No newline at end of file diff --git a/hapsigntool_cpp/hap/verify/include/verify_hap.h b/hapsigntool_cpp/hap/verify/include/verify_hap.h new file mode 100644 index 0000000000000000000000000000000000000000..bf0cb74488095dd4478f87dc172de0bfa1921110 --- /dev/null +++ b/hapsigntool_cpp/hap/verify/include/verify_hap.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024-2024 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_HAP_V2_H +#define SIGNATRUETOOLS_VERIFY_HAP_V2_H +#include + +#include "byte_buffer.h" +#include "random_access_file.h" +#include "hap_verify_result.h" +#include "profile_verify.h" +#include "verify_hap_openssl_utils.h" +#include "signature_info.h" +#include "options.h" +#include "file_utils.h" + +namespace OHOS { +namespace SignatureTools { +class VerifyHap { +public: + static const int32_t HEX_PRINT_LENGTH; + static const int32_t DIGEST_BLOCK_LEN_OFFSET; + static const int32_t DIGEST_ALGORITHM_OFFSET; + static const int32_t DIGEST_LEN_OFFSET; + static const int32_t DIGEST_OFFSET_IN_CONTENT; + static const std::string HAP_APP_PATTERN; + static const std::string HQF_APP_PATTERN; + static const std::string HSP_APP_PATTERN; + static const std::string APP_APP_PATTERN; + static const int OFFSET_ZERO = 0; + static const int OFFSET_FOUR = 4; + static const int OFFSET_EIGHT = 8; + int32_t Verify(const std::string& filePath, HapVerifyResult& hapVerifyV1Result, Options* options); + + DLL_EXPORT bool CheckFilePath(const std::string& filePath, std::string& standardFilePath); + static bool HapOutPutPkcs7(PKCS7* p7, const std::string& outPutPath); + static bool HapOutPutCertChain(std::vector& certs, const std::string& outPutPath); + int32_t VerifyElfProfile(std::vector& profileData, HapVerifyResult& hapVerifyV1Result, + Options* options, Pkcs7Context& pkcs7Context); + int32_t WriteVerifyOutput(Pkcs7Context& pkcs7Context, std::vector profile, Options* options); + int32_t InithapVerify(RandomAccessFile& hapFile, const std::string& filePath, + SignatureInfo& hapSignInfo, HapVerifyResult& hapVerifyV1Result); + int32_t Verify(RandomAccessFile& hapFile, HapVerifyResult& hapVerifyV1Result, Options* options, + const std::string& filePath); + bool CheckCodeSign(const std::string& hapFilePath, const std::vector& optionalBlocks)const; + static int GetProfileContent(const std::string profile, std::string& ret); + bool VerifyAppSourceAndParseProfile(Pkcs7Context& pkcs7Context, const ByteBuffer& hapProfileBlock, + HapVerifyResult& hapVerifyV1Result, bool& profileNeadWriteCrl); + bool VerifyAppPkcs7(Pkcs7Context& pkcs7Context, const ByteBuffer& hapSignatureBlock); + DLL_EXPORT bool GetDigestAndAlgorithm(Pkcs7Context& digest); + DLL_EXPORT bool ParseAndVerifyProfileIfNeed(const std::string& profile, ProfileInfo& provisionInfo, + bool isCallParseAndVerify); + bool IsAppDistributedTypeAllowInstall(const AppDistType& type, const ProfileInfo& provisionInfo) const; + DLL_EXPORT bool VerifyProfileInfo(const Pkcs7Context& pkcs7Context, const Pkcs7Context& profileContext, + ProfileInfo& provisionInfo); + DLL_EXPORT bool GenerateAppId(ProfileInfo& provisionInfo); + DLL_EXPORT bool GenerateFingerprint(ProfileInfo& provisionInfo); + bool VerifyProfileSignature(const Pkcs7Context& pkcs7Context, Pkcs7Context& profileContext); + void SetProfileBlockData(const Pkcs7Context& pkcs7Context, const ByteBuffer& hapProfileBlock, + ProfileInfo& provisionInfo); + void SetOrganization(ProfileInfo& provisionInfo); + bool NeedParseJson(const ByteBuffer& buffer); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_VERIFY_HAP_V2_H \ No newline at end of file diff --git a/hapsigntool_cpp/hap/verify/src/hap_verify_result.cpp b/hapsigntool_cpp/hap/verify/src/hap_verify_result.cpp new file mode 100644 index 0000000000000000000000000000000000000000..292d507b432cde4261d7e24aba131c2a4cdd2393 --- /dev/null +++ b/hapsigntool_cpp/hap/verify/src/hap_verify_result.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2024-2024 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 "hap_signer_block_utils.h" +#include "hap_verify_result.h" + +namespace OHOS { +namespace SignatureTools { +HapVerifyResult::HapVerifyResult() + : version(0), publicKeys(), signatures(), pkcs7SignBlock(), + pkcs7ProfileBlock(), optionalBlocks(), provisionInfo() +{ +} + +HapVerifyResult::~HapVerifyResult() +{ +} + +int32_t HapVerifyResult::GetVersion() const +{ + return version; +} + +void HapVerifyResult::SetVersion(int32_t signatureVersion) +{ + version = signatureVersion; +} + +void HapVerifyResult::SetPkcs7SignBlock(const ByteBuffer& pkcs7) +{ + pkcs7SignBlock = pkcs7; +} + +void HapVerifyResult::SetPkcs7ProfileBlock(const ByteBuffer& pkcs7) +{ + pkcs7ProfileBlock = pkcs7; +} + +void HapVerifyResult::SetOptionalBlocks(const std::vector& option) +{ + optionalBlocks = option; +} + +std::vector HapVerifyResult::GetPublicKey() const +{ + return publicKeys; +} + +std::vector HapVerifyResult::GetSignature() const +{ + return signatures; +} + +void HapVerifyResult::SetPublicKey(const std::vector& inputPubkeys) +{ + publicKeys = inputPubkeys; +} + +void HapVerifyResult::SetSignature(const std::vector& inputSignatures) +{ + signatures = inputSignatures; +} + +int32_t HapVerifyResult::GetProperty(std::string& property) const +{ + return GetBlockFromOptionalBlocks(PROPERTY_BLOB, property); +} + +int32_t HapVerifyResult::GetBlockFromOptionalBlocks(int32_t blockType, std::string& block) const +{ + for (unsigned long i = 0; i < optionalBlocks.size(); i++) { + if (optionalBlocks[i].optionalType == blockType) { + const ByteBuffer& option = optionalBlocks[i].optionalBlockValue; + block += std::string(option.GetBufferPtr(), option.GetCapacity()); + return GET_SUCCESS; + } + } + return NO_THIS_BLOCK_IN_PACKAGE; +} + +void HapVerifyResult::SetProvisionInfo(const ProfileInfo& info) +{ + provisionInfo = info; +} + +ProfileInfo HapVerifyResult::GetProvisionInfo() const +{ + return provisionInfo; +} + +std::vector HapVerifyResult::GetProfile() const +{ + return profile; +} + +void HapVerifyResult::SetProfile(std::vector profile) +{ + this->profile = profile; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/hap/verify/src/verify_bin.cpp b/hapsigntool_cpp/hap/verify/src/verify_bin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..243fc3b20019b23d7f8a3f4f0da1696b217ee36b --- /dev/null +++ b/hapsigntool_cpp/hap/verify/src/verify_bin.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2024-2024 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_bin.h" +#include "verify_hap.h" +#include "constant.h" + +namespace OHOS { +namespace SignatureTools { + +bool VerifyBin::Verify(Options* options) +{ + // check param + if (options == nullptr) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "Param options is null."); + return false; + } + if (!VerifyElf::CheckParams(options)) { + SIGNATURE_TOOLS_LOGE("verify bin check params failed!"); + return false; + } + std::string filePath = options->GetString(Options::IN_FILE); + bool checkSignFileFlag = VerifyElf::CheckSignFile(filePath); + if (!checkSignFileFlag) { + SIGNATURE_TOOLS_LOGE("check input bin file %s failed!", filePath.c_str()); + return false; + } + // verify bin + HapVerifyResult verifyResult; + Pkcs7Context pkcs7Context; + bool verifyBinFileFLag = VerifyBinFile(filePath, verifyResult, options, pkcs7Context); + if (!verifyBinFileFLag) { + SIGNATURE_TOOLS_LOGE("verify bin file %s failed!", filePath.c_str()); + return false; + } + // write certificate and p7b file + VerifyHap hapVerifyV2; + int32_t writeFlag = hapVerifyV2.WriteVerifyOutput(pkcs7Context, verifyResult.GetProfile(), options); + if (writeFlag != VERIFY_SUCCESS) { + SIGNATURE_TOOLS_LOGE("write elf output failed on verify bin!"); + return false; + } + return true; +} + +bool VerifyBin::VerifyBinFile(const std::string& binFile, HapVerifyResult& verifyResult, + Options* options, Pkcs7Context& pkcs7Context) +{ + SignBlockInfo signBlockInfo(true); + bool getSignBlockInfoFlag = VerifyElf::GetSignBlockInfo(binFile, signBlockInfo, BIN); + if (!getSignBlockInfoFlag) { + SIGNATURE_TOOLS_LOGE("get signBlockInfo failed on verify bin %s", binFile.c_str()); + return false; + } + // verify profile + std::string profileJson; + bool verifyP7bFlag = VerifyElf::VerifyP7b(signBlockInfo.GetSignBlockMap(), options, pkcs7Context, + verifyResult, profileJson); + if (!verifyP7bFlag) { + SIGNATURE_TOOLS_LOGE("verify profile failed on verify bin %s", binFile.c_str()); + return false; + } + // verify signed data + bool verifyBinDigestFlag = VerifyBinDigest(signBlockInfo); + if (!verifyBinDigestFlag) { + SIGNATURE_TOOLS_LOGE("verify digest failed on verify bin %s", binFile.c_str()); + return false; + } + return true; +} + +bool VerifyBin::VerifyBinDigest(SignBlockInfo& signBlockInfo) +{ + std::vector rawDigest = signBlockInfo.GetRawDigest(); + std::vector generatedDig = signBlockInfo.GetFileDigest(); + bool isEqual = rawDigest.empty() || generatedDig.empty() || + !std::equal(rawDigest.begin(), rawDigest.end(), generatedDig.begin()); + if (isEqual) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "compare bin file raw digest and generated digest failed!"); + return false; + } + return true; +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/hap/verify/src/verify_elf.cpp b/hapsigntool_cpp/hap/verify/src/verify_elf.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31eefa1175b6ff521791c649b3941456ad3da65a --- /dev/null +++ b/hapsigntool_cpp/hap/verify/src/verify_elf.cpp @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2024-2024 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 "constant.h" +#include "file_utils.h" +#include "hw_sign_head.h" +#include "hw_block_head.h" +#include "verify_hap.h" +#include "verify_code_signature.h" +#include "hash_utils.h" +#include "sign_content_info.h" +#include "signature_block_tags.h" +#include "verify_elf.h" + +namespace OHOS { +namespace SignatureTools { + +const int8_t VerifyElf::SIGNATURE_BLOCK = 0; +const int8_t VerifyElf::PROFILE_NOSIGNED_BLOCK = 1; +const int8_t VerifyElf::PROFILE_SIGNED_BLOCK = 2; +const int8_t VerifyElf::KEY_ROTATION_BLOCK = 3; +const int8_t VerifyElf::CODESIGNING_BLOCK_TYPE = 3; + +bool VerifyElf::Verify(Options* options) +{ + // check param + if (options == nullptr) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "Param options is null."); + return false; + } + if (!CheckParams(options)) { + SIGNATURE_TOOLS_LOGE("verify elf check params failed!"); + return false; + } + std::string filePath = options->GetString(Options::IN_FILE); + bool checkSignFileFlag = CheckSignFile(filePath); + if (!checkSignFileFlag) { + SIGNATURE_TOOLS_LOGE("check input elf file %s failed!", filePath.c_str()); + return false; + } + // verify elf + HapVerifyResult verifyResult; + Pkcs7Context pkcs7Context; + bool verifyElfFileFlag = VerifyElfFile(filePath, verifyResult, options, pkcs7Context); + if (!verifyElfFileFlag) { + SIGNATURE_TOOLS_LOGE("verify elf file %s failed!", filePath.c_str()); + return false; + } + // write certificate and p7b file + VerifyHap hapVerifyV2; + int32_t writeVerifyOutputFlag = hapVerifyV2.WriteVerifyOutput(pkcs7Context, verifyResult.GetProfile(), options); + if (writeVerifyOutputFlag != VERIFY_SUCCESS) { + SIGNATURE_TOOLS_LOGE("write elf output failed on verify elf!"); + return false; + } + return true; +} + +bool VerifyElf::VerifyElfFile(const std::string& elfFile, HapVerifyResult& verifyResult, + Options* options, Pkcs7Context& pkcs7Context) +{ + SignBlockInfo signBlockInfo(false); + bool getSignBlockInfoFlag = GetSignBlockInfo(elfFile, signBlockInfo, ELF); + if (!getSignBlockInfoFlag) { + SIGNATURE_TOOLS_LOGE("get signBlockInfo failed on verify elf %s", elfFile.c_str()); + return false; + } + // verify profile + std::string profileJson; + bool verifyP7b = VerifyP7b(signBlockInfo.GetSignBlockMap(), options, pkcs7Context, verifyResult, profileJson); + if (!verifyP7b) { + SIGNATURE_TOOLS_LOGE("verify profile failed on verify elf %s", elfFile.c_str()); + return false; + } + // verify code sign + bool findFlag = + signBlockInfo.GetSignBlockMap().find(CODESIGNING_BLOCK_TYPE) != signBlockInfo.GetSignBlockMap().end(); + if (findFlag) { + SigningBlock codesign = signBlockInfo.GetSignBlockMap().find(CODESIGNING_BLOCK_TYPE)->second; + bool verifyElfFlag = VerifyCodeSignature::VerifyElf(elfFile, codesign.GetOffset(), codesign.GetLength(), + ELF, profileJson); + if (!verifyElfFlag) { + SIGNATURE_TOOLS_LOGE("code signing failed on verify elf %s", elfFile.c_str()); + return false; + } + } + return true; +} + +bool VerifyElf::VerifyP7b(std::unordered_map& signBlockMap, + Options* options, Pkcs7Context& pkcs7Context, + HapVerifyResult& verifyResult, std::string& profileJson) +{ + if (signBlockMap.find(PROFILE_NOSIGNED_BLOCK) != signBlockMap.end()) { + // verify unsigned profile + std::vector profileByte = signBlockMap.find(PROFILE_NOSIGNED_BLOCK)->second.GetValue(); + std::string fromByteStr(profileByte.begin(), profileByte.end()); + profileJson = fromByteStr; + verifyResult.SetProfile(profileByte); + SIGNATURE_TOOLS_LOGW("profile is not signed."); + } else if (signBlockMap.find(PROFILE_SIGNED_BLOCK) != signBlockMap.end()) { + // verify signed profile + SigningBlock profileSign = signBlockMap.find(PROFILE_SIGNED_BLOCK)->second; + std::vector profileByte = profileSign.GetValue(); + bool getRawContentFlag = GetRawContent(profileByte, profileJson); + if (!getRawContentFlag) { + SIGNATURE_TOOLS_LOGE("get profile content failed on verify elf!"); + return false; + } + VerifyHap hapVerifyV2; + int32_t resultCode = hapVerifyV2.VerifyElfProfile(profileByte, verifyResult, options, pkcs7Context); + if (resultCode != VERIFY_SUCCESS) { + SIGNATURE_TOOLS_LOGE("verify elf profile failed on verify elf!"); + return false; + } + verifyResult.SetProfile(profileByte); + SIGNATURE_TOOLS_LOGI("verify profile success."); + } else { + SIGNATURE_TOOLS_LOGW("can not found profile sign block."); + } + return true; +} + +bool VerifyElf::GetSignBlockInfo(const std::string& file, SignBlockInfo& signBlockInfo, + const std::string fileType) +{ + // read file + std::uintmax_t fileSize = std::filesystem::file_size(file); + std::ifstream fileStream(file, std::ios::binary); + if (!fileStream.is_open()) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open file: " + file + "failed"); + return false; + } + std::vector* fileBytes = new std::vector(fileSize, 0); + fileStream.read(fileBytes->data(), fileBytes->size()); + if (fileStream.fail() && !fileStream.eof()) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "Error occurred while reading data"); + fileStream.close(); + return false; + } + fileStream.close(); + // get HwBlockData + HwBlockData hwBlockData(0, 0); + bool getSignBlockData = GetSignBlockData(*((std::vector*)fileBytes), hwBlockData, fileType); + if (!getSignBlockData) { + SIGNATURE_TOOLS_LOGE("get signBlockData failed on verify elf/bin file %s", file.c_str()); + delete fileBytes; + return false; + } + // get SignBlockMap + if (fileType == ELF) { + GetElfSignBlock(*((std::vector*)fileBytes), hwBlockData, signBlockInfo.GetSignBlockMap()); + } else { + GetBinSignBlock(*((std::vector*)fileBytes), hwBlockData, signBlockInfo.GetSignBlockMap()); + } + // get bin file digest + bool needGenerateDigest = signBlockInfo.GetNeedGenerateDigest(); + if (needGenerateDigest) { + std::vector signatrue = signBlockInfo.GetSignBlockMap().find(0)->second.GetValue(); + bool getFileDigest = GetFileDigest(*((std::vector*)fileBytes), signatrue, signBlockInfo); + if (!getFileDigest) { + SIGNATURE_TOOLS_LOGE("getFileDigest failed on verify bin file %s", file.c_str()); + delete fileBytes; + return false; + } + } + delete fileBytes; + return true; +} + +bool VerifyElf::GetFileDigest(std::vector& fileBytes, std::vector& signatrue, + SignBlockInfo& signBlockInfo) +{ + std::string binDigest; + bool getRawContentFlag = GetRawContent(signatrue, binDigest); + if (!getRawContentFlag) { + SIGNATURE_TOOLS_LOGE("getBinDigest failed on verify bin digest!"); + return false; + } + std::vector rawDigest(binDigest.begin(), binDigest.end()); + signBlockInfo.SetRawDigest(rawDigest); + GenerateFileDigest(fileBytes, signBlockInfo); + return true; +} + +bool VerifyElf::GenerateFileDigest(std::vector& fileBytes, SignBlockInfo& signBlockInfo) +{ + // get algId + std::vector rawDigest = signBlockInfo.GetRawDigest(); + std::unique_ptr digBuffer = std::make_unique(rawDigest.size()); + digBuffer->PutData(rawDigest.data(), rawDigest.size()); + digBuffer->Flip(); + int32_t algOffset = 10; + int16_t algId = 0; + const char* bufferPtr = digBuffer->GetBufferPtr(); + algId = static_cast(be16toh(*reinterpret_cast(bufferPtr + algOffset))); + // generate digest + int32_t fileLength = signBlockInfo.GetSignBlockMap().find(0)->second.GetOffset(); + std::string digAlg = HashUtils::GetHashAlgName(algId); + std::vector generatedDig = HashUtils::GetDigestFromBytes(fileBytes, fileLength, digAlg); + if (generatedDig.empty()) { + SIGNATURE_TOOLS_LOGE("generate bin file digest failed on verify bin"); + return false; + } + SignContentInfo contentInfo; + contentInfo.AddContentHashData(0, SignatureBlockTags::HASH_ROOT_4K, algId, generatedDig.size(), generatedDig); + std::vector dig = contentInfo.GetByteContent(); + if (dig.empty()) { + SIGNATURE_TOOLS_LOGE("generate file digest is null on verify bin"); + return false; + } + signBlockInfo.SetFileDigest(dig); + return true; +} + +bool VerifyElf::GetSignBlockData(std::vector& bytes, HwBlockData& hwBlockData, + const std::string fileType) +{ + int64_t offset = 0; + bool checkMagicAndVersionFlag = CheckMagicAndVersion(bytes, offset, fileType); + if (!checkMagicAndVersionFlag) { + SIGNATURE_TOOLS_LOGE("check magic and version failed, file type: %s", fileType.c_str()); + return false; + } + int32_t intByteLength = 4; + std::vector blockSizeByte(bytes.begin() + offset, bytes.begin() + offset + intByteLength); + offset += intByteLength; + std::vector blockNumByte(bytes.begin() + offset, bytes.begin() + offset + intByteLength); + if (fileType == BIN) { + std::reverse(blockSizeByte.begin(), blockSizeByte.end()); + std::reverse(blockNumByte.begin(), blockNumByte.end()); + } + std::unique_ptr blockNumBf = std::make_unique(blockNumByte.size()); + blockNumBf->PutData(blockNumByte.data(), blockNumByte.size()); + blockNumBf->Flip(); + int32_t blockNum = 0; + blockNumBf->GetInt32(blockNum); + std::unique_ptr blockSizeBf = std::make_unique(blockSizeByte.size()); + blockSizeBf->PutData(blockSizeByte.data(), blockSizeByte.size()); + blockSizeBf->Flip(); + int32_t blockSize = 0; + blockSizeBf->GetInt32(blockSize); + int64_t blockStart = 0; + if (fileType == BIN) { + blockStart = bytes.size() - blockSize; + } else { + blockStart = bytes.size() - HwSignHead::SIGN_HEAD_LEN - blockSize; + } + hwBlockData.SetBlockNum(blockNum); + hwBlockData.SetBlockStart(blockStart); + return true; +} + +bool VerifyElf::CheckMagicAndVersion(std::vector& bytes, int64_t& offset, const std::string fileType) +{ + std::string magicStr = (fileType == ELF ? HwSignHead::ELF_MAGIC : HwSignHead::MAGIC); + offset = bytes.size() - HwSignHead::SIGN_HEAD_LEN; + std::vector magicByte(bytes.begin() + offset, bytes.begin() + offset + magicStr.size()); + offset += magicStr.size(); + std::vector versionByte(bytes.begin() + offset, bytes.begin() + offset + HwSignHead::VERSION.size()); + offset += HwSignHead::VERSION.size(); + std::vector magicVec(magicStr.begin(), magicStr.end()); + for (int i = 0; i < magicStr.size(); i++) { + if (magicVec[i] != magicByte[i]) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "magic verify failed!"); + return false; + } + } + std::vector versionVec(HwSignHead::VERSION.begin(), HwSignHead::VERSION.end()); + for (int i = 0; i < HwSignHead::VERSION.size(); i++) { + if (versionVec[i] != versionByte[i]) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "sign version verify failed!"); + return false; + } + } + return true; +} + +void VerifyElf::GetElfSignBlock(std::vector& bytes, HwBlockData& hwBlockData, + std::unordered_map& signBlockMap) +{ + int32_t headBlockLen = HwSignHead::ELF_BLOCK_LEN; + int64_t offset = hwBlockData.GetBlockStart(); + for (int i = 0; i < hwBlockData.GetBlockNum(); i++) { + std::vector blockByte(bytes.begin() + offset, bytes.begin() + offset + headBlockLen); + std::unique_ptr blockBuffer = std::make_unique(blockByte.size()); + blockBuffer->PutData(blockByte.data(), blockByte.size()); + blockBuffer->Flip(); + int8_t type = 0; + int8_t tag = 0; + int16_t empValue = 0; + int32_t length = 0; + int32_t blockOffset = 0; + blockBuffer->GetByte((int8_t*)&type, sizeof(int8_t)); + blockBuffer->GetByte((int8_t*)&tag, sizeof(int8_t)); + blockBuffer->GetInt16(empValue); + blockBuffer->GetInt32(length); + blockBuffer->GetInt32(blockOffset); + std::vector value(bytes.begin() + hwBlockData.GetBlockStart() + blockOffset, + bytes.begin() + hwBlockData.GetBlockStart() + blockOffset + length); + SigningBlock signingBlock(type, value, hwBlockData.GetBlockStart() + blockOffset); + signBlockMap.insert(std::make_pair(type, signingBlock)); + offset += headBlockLen; + } +} + +void VerifyElf::GetBinSignBlock(std::vector& bytes, HwBlockData& hwBlockData, + std::unordered_map& signBlockMap) +{ + int32_t headBlockLen = HwSignHead::BIN_BLOCK_LEN; + int32_t offset = hwBlockData.GetBlockStart(); + for (int i = 0; i < hwBlockData.GetBlockNum(); i++) { + std::vector blockByte(bytes.begin() + offset, bytes.begin() + offset + headBlockLen); + std::unique_ptr blockBuffer = std::make_unique(blockByte.size()); + blockBuffer->PutData(blockByte.data(), blockByte.size()); + blockBuffer->Flip(); + int8_t type = 0; + int8_t tag = 0; + int16_t length = 0; + int32_t blockOffset = 0; + blockBuffer->GetByte((int8_t*)&type, sizeof(int8_t)); + blockBuffer->GetByte((int8_t*)&tag, sizeof(int8_t)); + const char* bufferPtr = blockBuffer->GetBufferPtr(); + int bfLengthIdx = 2; + int bfBlockIdx = 4; + length = static_cast(be16toh(*reinterpret_cast(bufferPtr + bfLengthIdx))); + blockOffset = static_cast(be32toh(*reinterpret_cast(bufferPtr + bfBlockIdx))); + if (length == 0) { + length = bytes.size() - HwSignHead::SIGN_HEAD_LEN - blockOffset; + } + std::vector value(bytes.begin() + blockOffset, bytes.begin() + blockOffset + length); + SigningBlock signingBlock(type, value, blockOffset); + signBlockMap.insert(std::make_pair(type, signingBlock)); + offset += headBlockLen; + } +} + +bool VerifyElf::CheckParams(Options* options) +{ + bool certEmpty = options->GetString(Options::OUT_CERT_CHAIN).empty(); + if (certEmpty) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "Missing parameter: " + Options::OUT_CERT_CHAIN + "s."); + return false; + } + bool profileEmpty = options->GetString(Options::OUT_PROFILE).empty(); + if (profileEmpty) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "Missing parameter: " + Options::OUT_PROFILE + "s."); + return false; + } + bool proofEmpty = options->GetString(Options::PROOF_FILE).empty(); + if (proofEmpty) { + SIGNATURE_TOOLS_LOGW("Missing parameter: %s.", + Options::PROOF_FILE.c_str()); + } + return true; +} + +bool VerifyElf::CheckSignFile(const std::string& signedFile) +{ + if (signedFile.empty()) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "Not found verify file path " + signedFile); + return false; + } + bool validFlag = FileUtils::IsValidFile(signedFile); + if (!validFlag) { + SIGNATURE_TOOLS_LOGE("signed file is invalid."); + return false; + } + return true; +} + +bool VerifyElf::GetRawContent(std::vector& contentVec, std::string& rawContent) +{ + PKCS7Data p7Data; + int parseFlag = p7Data.Parse(contentVec); + if (parseFlag < 0) { + SIGNATURE_TOOLS_LOGE("parse content failed!"); + return false; + } + int verifyFlag = p7Data.Verify(); + if (verifyFlag < 0) { + SIGNATURE_TOOLS_LOGE("verify content failed!"); + return false; + } + int getContentFlag = p7Data.GetContent(rawContent); + if (getContentFlag < 0) { + SIGNATURE_TOOLS_LOGE("get p7Data raw content failed!"); + return false; + } + return true; +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/hap/verify/src/verify_hap.cpp b/hapsigntool_cpp/hap/verify/src/verify_hap.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1dca2fbb1c8e4c9a398b268607ee94440402f599 --- /dev/null +++ b/hapsigntool_cpp/hap/verify/src/verify_hap.cpp @@ -0,0 +1,601 @@ +/* + * Copyright (c) 2024-2024 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 + +#include "securec.h" +#include "profile_verify_utils.h" +#include "hap_signer_block_utils.h" +#include "signature_info.h" +#include "options.h" +#include "openssl/pem.h" +#include "pkcs7_data.h" +#include "hap_utils.h" +#include "string_utils.h" +#include "verify_code_signature.h" +#include "param_constants.h" +#include "file_utils.h" +#include "nlohmann/json.hpp" +#include "verify_hap.h" + +using namespace nlohmann; +namespace OHOS { +namespace SignatureTools { +const int32_t VerifyHap::HEX_PRINT_LENGTH = 3; +const int32_t VerifyHap::DIGEST_BLOCK_LEN_OFFSET = 8; +const int32_t VerifyHap::DIGEST_ALGORITHM_OFFSET = 12; +const int32_t VerifyHap::DIGEST_LEN_OFFSET = 16; +const int32_t VerifyHap::DIGEST_OFFSET_IN_CONTENT = 20; +const std::string VerifyHap::HAP_APP_PATTERN = "[^]*.hap$"; +const std::string VerifyHap::HQF_APP_PATTERN = "[^]*.hqf$"; +const std::string VerifyHap::HSP_APP_PATTERN = "[^]*.hsp$"; +const std::string VerifyHap::APP_APP_PATTERN = "[^]*.app$"; +static constexpr int ZIP_HEAD_OF_SUBSIGNING_BLOCK_LENGTH = 12; +bool VerifyHap::HapOutPutPkcs7(PKCS7* p7, const std::string& outPutPath) +{ + std::string p7bContent = StringUtils::Pkcs7ToString(p7); + if (p7bContent.empty()) { + SIGNATURE_TOOLS_LOGE("p7b to string failed!\n"); + return false; + } + if (FileUtils::Write(p7bContent, outPutPath) < 0) { + SIGNATURE_TOOLS_LOGE("p7b write to file falied!\n"); + return false; + } + return true; +} + +bool VerifyHap::HapOutPutCertChain(std::vector& certs, const std::string& outPutPath) +{ + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGD("outPutPath = %s", outPutPath.c_str()); + std::vector certStr; + for (auto& cert : certs) { + certStr.emplace_back(StringUtils::SubjectToString(cert)); + certStr.emplace_back(StringUtils::x509CertToString(cert)); + } + std::string outPutCertChainContent; + for (auto& certstr : certStr) { + outPutCertChainContent += certstr; + } + if (FileUtils::Write(outPutCertChainContent, outPutPath) < 0) { + SIGNATURE_TOOLS_LOGE("certChain write to file falied!\n"); + return false; + } + return true; +} + +int32_t VerifyHap::Verify(const std::string& filePath, HapVerifyResult& hapVerifyV1Result, Options* options) +{ + SIGNATURE_TOOLS_LOGD("Start Verify"); + std::string standardFilePath; + if (!CheckFilePath(filePath, standardFilePath)) { + SIGNATURE_TOOLS_LOGE("Check file path%s failed", filePath.c_str()); + return FILE_PATH_INVALID; + } + RandomAccessFile hapFile; + if (!hapFile.Init(standardFilePath)) { + SIGNATURE_TOOLS_LOGE("%s init failed", standardFilePath.c_str()); + return OPEN_FILE_ERROR; + } + int32_t resultCode = Verify(hapFile, hapVerifyV1Result, options, filePath); + if (resultCode != VERIFY_SUCCESS) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, standardFilePath + " verify failed"); + } + return resultCode; +} + +bool VerifyHap::CheckFilePath(const std::string& filePath, std::string& standardFilePath) +{ + char path[PATH_MAX] = { 0x00 }; + if (filePath.size() > PATH_MAX || realpath(filePath.c_str(), path) == nullptr) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, + filePath + " does not exist or is over " + std::to_string(PATH_MAX) + " chars"); + return false; + } + standardFilePath = std::string(path); + bool ret = (!std::regex_match(standardFilePath, std::regex(HAP_APP_PATTERN)) && + !std::regex_match(standardFilePath, std::regex(HSP_APP_PATTERN)) && + !std::regex_match(standardFilePath, std::regex(APP_APP_PATTERN)) && + !std::regex_match(standardFilePath, std::regex(HQF_APP_PATTERN))); + if (ret) { + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, + "only support format is [hap, hqf, hsp, app]"); + return false; + } + return true; +} + +int32_t VerifyHap::InithapVerify(RandomAccessFile& hapFile, const std::string& filePath, + SignatureInfo& hapSignInfo, HapVerifyResult& hapVerifyV1Result) +{ + if (!HapSignerBlockUtils::FindHapSignature(hapFile, hapSignInfo)) { + return SIGNATURE_NOT_FOUND; + } + if (CheckCodeSign(filePath, hapSignInfo.optionBlocks) == false) { + SIGNATURE_TOOLS_LOGE("check coode sign failed\n"); + return VERIFY_CODE_SIGN_FAIL; + } + hapVerifyV1Result.SetVersion(hapSignInfo.version); + hapVerifyV1Result.SetPkcs7SignBlock(hapSignInfo.hapSignatureBlock); + hapVerifyV1Result.SetPkcs7ProfileBlock(hapSignInfo.hapSignatureBlock); + hapVerifyV1Result.SetOptionalBlocks(hapSignInfo.optionBlocks); + return VERIFY_SUCCESS; +} + +int32_t VerifyHap::Verify(RandomAccessFile& hapFile, HapVerifyResult& hapVerifyV1Result, + Options* options, const std::string& filePath) +{ + SignatureInfo hapSignInfo; + if (InithapVerify(hapFile, filePath, hapSignInfo, hapVerifyV1Result) != VERIFY_SUCCESS) { + return SIGNATURE_NOT_FOUND; + } + Pkcs7Context pkcs7Context; + if (!VerifyAppPkcs7(pkcs7Context, hapSignInfo.hapSignatureBlock)) { + return VERIFY_APP_PKCS7_FAIL; + } + int32_t profileIndex = 0; + if (!HapSignerBlockUtils::GetOptionalBlockIndex(hapSignInfo.optionBlocks, PROFILE_BLOB, profileIndex)) { + return NO_PROFILE_BLOCK_FAIL; + } + bool profileNeedWriteCrl = false; + if (!VerifyAppSourceAndParseProfile(pkcs7Context, hapSignInfo.optionBlocks[profileIndex].optionalBlockValue, + hapVerifyV1Result, profileNeedWriteCrl)) { + SIGNATURE_TOOLS_LOGE("APP source is not trusted"); + return APP_SOURCE_NOT_TRUSTED; + } + if (!GetDigestAndAlgorithm(pkcs7Context)) { + SIGNATURE_TOOLS_LOGE("Get digest failed"); + return GET_DIGEST_FAIL; + } + std::vector publicKeys; + if (!VerifyHapOpensslUtils::GetPublickeys(pkcs7Context.certChains[0], publicKeys)) { + SIGNATURE_TOOLS_LOGE("Get publicKeys failed"); + return GET_PUBLICKEY_FAIL; + } + hapVerifyV1Result.SetPublicKey(publicKeys); + std::vector certSignatures; + if (!VerifyHapOpensslUtils::GetSignatures(pkcs7Context.certChains[0], certSignatures)) { + SIGNATURE_TOOLS_LOGE("Get sianatures failed"); + return GET_SIGNATURE_FAIL; + } + hapVerifyV1Result.SetSignature(certSignatures); + if (!HapSignerBlockUtils::VerifyHapIntegrity(pkcs7Context, hapFile, hapSignInfo)) { + SIGNATURE_TOOLS_LOGE("Verify Integrity failed"); + return VERIFY_INTEGRITY_FAIL; + } + if (!VerifyHap::HapOutPutCertChain(pkcs7Context.certChains[0], + options->GetString(Options::OUT_CERT_CHAIN))) { + SIGNATURE_TOOLS_LOGE("out put cert chain failed"); + return OUT_PUT_FILE_FAIL; + } + if (!VerifyHap::HapOutPutPkcs7(pkcs7Context.p7, options->GetString(Options::OUT_PROFILE))) { + SIGNATURE_TOOLS_LOGE("out put p7b failed"); + return OUT_PUT_FILE_FAIL; + } + return VERIFY_SUCCESS; +} + +bool VerifyHap::CheckCodeSign(const std::string& hapFilePath, + const std::vector& optionalBlocks)const +{ + std::unordered_map map; + for (const OptionalBlock& block : optionalBlocks) { + map.emplace(block.optionalType, block.optionalBlockValue); + } + bool codeSignFlag = map.find(HapUtils::HAP_PROPERTY_BLOCK_ID) != map.end() && + map[HapUtils::HAP_PROPERTY_BLOCK_ID].GetCapacity() > 0; + if (codeSignFlag) { + ByteBuffer propertyBlockArray = map[HapUtils::HAP_PROPERTY_BLOCK_ID]; + std::vector fileNameArray = StringUtils::SplitString(hapFilePath, '.'); + if (fileNameArray.size() < ParamConstants::FILE_NAME_MIN_LENGTH) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "ZIP64 format not supported."); + return false; + } + + if (propertyBlockArray.GetCapacity() < ZIP_HEAD_OF_SUBSIGNING_BLOCK_LENGTH) + return false; + uint32_t blockType; + propertyBlockArray.GetUInt32(OFFSET_ZERO, blockType); + uint32_t blockLength; + propertyBlockArray.GetUInt32(OFFSET_FOUR, blockLength); + uint32_t blockOffset; + propertyBlockArray.GetUInt32(OFFSET_EIGHT, blockOffset); + + if (blockType != HapUtils::HAP_CODE_SIGN_BLOCK_ID) { + PrintErrorNumberMsg("VERIFY_ERROR", VERIFY_ERROR, "code sign data not exist in hap " + hapFilePath); + return false; + } + auto ite = map.find(HapUtils::HAP_PROFILE_BLOCK_ID); + if (ite == map.end()) + return false; + ByteBuffer profileArray = ite->second; + std::string profileArray_(profileArray.GetBufferPtr(), profileArray.GetCapacity()); + std::string profileContent; + if (GetProfileContent(profileArray_, profileContent) < 0) { + SIGNATURE_TOOLS_LOGE("get profile content failed, file: %s", hapFilePath.c_str()); + return false; + } + std::string suffix = fileNameArray[fileNameArray.size() - 1]; + bool isCodeSign = VerifyCodeSignature::VerifyHap(hapFilePath, blockOffset, blockLength, + suffix, profileContent); + if (!isCodeSign) { + SIGNATURE_TOOLS_LOGE("verify codesign failed, file: %s", hapFilePath.c_str()); + return false; + } + SIGNATURE_TOOLS_LOGI("verify codesign success."); + return true; + } + SIGNATURE_TOOLS_LOGI("can not find codesign block."); + return true; +} + +int VerifyHap::GetProfileContent(const std::string profile, std::string& ret) +{ + json obj = json::parse(profile, nullptr, false); + if (!obj.is_discarded() && obj.is_structured()) { + ret = profile; + return 0; + } + PKCS7Data p7Data; + if (p7Data.Parse(profile) < 0) { + PrintErrorNumberMsg("PKCS7_PARSE_ERROR", PARSE_ERROR, "Parse profile failed"); + ret = profile; + return -1; + } + if (p7Data.Verify() < 0) { + PrintErrorNumberMsg("PKCS7_VERIFY_ERROR", VERIFY_ERROR, + "Verify profile pkcs7 failed! Profile is invalid"); + ret = profile; + return -1; + } + if (p7Data.GetContent(ret) < 0) { + PrintErrorNumberMsg("PKCS7_VERIFY_ERROR", VERIFY_ERROR, + "Check profile failed, signed profile content is not byte array"); + ret = profile; + return -1; + } + return 0; +} + +bool VerifyHap::VerifyAppPkcs7(Pkcs7Context& pkcs7Context, const ByteBuffer& hapSignatureBlock) +{ + const unsigned char* pkcs7Block = reinterpret_cast(hapSignatureBlock.GetBufferPtr()); + uint32_t pkcs7Len = static_cast(hapSignatureBlock.GetCapacity()); + if (!VerifyHapOpensslUtils::ParsePkcs7Package(pkcs7Block, pkcs7Len, pkcs7Context)) { + SIGNATURE_TOOLS_LOGE("parse pkcs7 failed"); + return false; + } + if (!VerifyHapOpensslUtils::GetCertChains(pkcs7Context.p7, pkcs7Context)) { + SIGNATURE_TOOLS_LOGE("GetCertChains from pkcs7 failed"); + return false; + } + if (!VerifyHapOpensslUtils::VerifyPkcs7(pkcs7Context)) { + SIGNATURE_TOOLS_LOGE("verify signature failed"); + return false; + } + return true; +} + +bool VerifyHap::VerifyAppSourceAndParseProfile(Pkcs7Context& pkcs7Context, + const ByteBuffer& hapProfileBlock, + HapVerifyResult& hapVerifyV1Result, + bool& profileNeadWriteCrl) +{ + std::string certSubject; + if (!VerifyCertOpensslUtils::GetSubjectFromX509(pkcs7Context.certChains[0][0], certSubject)) { + SIGNATURE_TOOLS_LOGE("Get info of sign cert failed"); + return false; + } + SIGNATURE_TOOLS_LOGD("App signature subject: %s, issuer: %s", + certSubject.c_str(), pkcs7Context.certIssuer.c_str()); + if (!NeedParseJson(hapProfileBlock)) return true; + Pkcs7Context profileContext; + std::string profile; + if (!ProfileVerifyUtils::ParseProfile(profileContext, pkcs7Context, hapProfileBlock, profile)) { + SIGNATURE_TOOLS_LOGE("Parse profile pkcs7 failed"); + return false; + } + if (!VerifyProfileSignature(pkcs7Context, profileContext)) { + SIGNATURE_TOOLS_LOGE("VerifyProfileSignature failed"); + return false; + } + /* + * If app source is not trusted, verify profile. + * If profile is debug, check whether app signed cert is same as the debug cert in profile. + * If profile is release, do not allow installation of this app. + */ + bool isCallParseAndVerify = false; + ProfileInfo provisionInfo; + if (pkcs7Context.matchResult.matchState == DO_NOT_MATCH) { + if (!ProfileVerifyUtils::VerifyProfile(profileContext)) { + SIGNATURE_TOOLS_LOGE("profile verify failed"); + return false; + } + AppProvisionVerifyResult profileRet = ParseAndVerify(profile, provisionInfo); + if (profileRet != PROVISION_OK) { + SIGNATURE_TOOLS_LOGE("profile parsing failed, error: %d", static_cast(profileRet)); + return false; + } + if (!VerifyProfileInfo(pkcs7Context, profileContext, provisionInfo)) { + SIGNATURE_TOOLS_LOGE("VerifyProfileInfo failed"); + return false; + } + isCallParseAndVerify = true; + } + if (!ParseAndVerifyProfileIfNeed(profile, provisionInfo, isCallParseAndVerify)) { + return false; + } + if (!GenerateAppId(provisionInfo) || !GenerateFingerprint(provisionInfo)) { + SIGNATURE_TOOLS_LOGE("Generate appId or generate fingerprint failed"); + return false; + } + SetOrganization(provisionInfo); + SetProfileBlockData(pkcs7Context, hapProfileBlock, provisionInfo); + hapVerifyV1Result.SetProvisionInfo(provisionInfo); + profileNeadWriteCrl = profileContext.needWriteCrl; + return true; +} + +bool VerifyHap::NeedParseJson(const ByteBuffer& buffer) +{ + std::string profileArray_(buffer.GetBufferPtr(), buffer.GetCapacity()); + json obj = json::parse(profileArray_, nullptr, false); + if (!obj.is_discarded() && obj.is_structured()) { + return false; + } + return true; +} + +bool VerifyHap::VerifyProfileSignature(const Pkcs7Context& pkcs7Context, Pkcs7Context& profileContext) +{ + if (pkcs7Context.matchResult.matchState == MATCH_WITH_SIGN && + pkcs7Context.matchResult.source == APP_THIRD_PARTY_PRELOAD) { + if (!ProfileVerifyUtils::VerifyProfile(profileContext)) { + SIGNATURE_TOOLS_LOGE("profile verify failed"); + return false; + } + } + return true; +} + +bool VerifyHap::GenerateAppId(ProfileInfo& provisionInfo) +{ + std::string& certInProfile = provisionInfo.bundleInfo.distributionCertificate; + if (provisionInfo.bundleInfo.distributionCertificate.empty()) { + certInProfile = provisionInfo.bundleInfo.developmentCertificate; + SIGNATURE_TOOLS_LOGD("use development Certificate"); + } + std::string publicKey; + if (!VerifyCertOpensslUtils::GetPublickeyBase64FromPemCert(certInProfile, publicKey)) { + return false; + } + provisionInfo.appId = publicKey; + SIGNATURE_TOOLS_LOGD("provisionInfo.appId: %s", provisionInfo.appId.c_str()); + return true; +} + +bool VerifyHap::GenerateFingerprint(ProfileInfo& provisionInfo) +{ + std::string& certInProfile = provisionInfo.bundleInfo.distributionCertificate; + if (provisionInfo.bundleInfo.distributionCertificate.empty()) { + certInProfile = provisionInfo.bundleInfo.developmentCertificate; + SIGNATURE_TOOLS_LOGD("use development Certificate"); + } + std::string fingerprint; + if (!VerifyCertOpensslUtils::GetFingerprintBase64FromPemCert(certInProfile, fingerprint)) { + SIGNATURE_TOOLS_LOGE("Generate fingerprint from pem certificate failed"); + return false; + } + provisionInfo.fingerprint = fingerprint; + SIGNATURE_TOOLS_LOGD("fingerprint is : %s", fingerprint.c_str()); + return true; +} + +void VerifyHap::SetProfileBlockData(const Pkcs7Context& pkcs7Context, const ByteBuffer& hapProfileBlock, + ProfileInfo& provisionInfo) +{ + if (pkcs7Context.matchResult.matchState == MATCH_WITH_SIGN && + pkcs7Context.matchResult.source == APP_GALLARY) { + SIGNATURE_TOOLS_LOGD("profile is from app gallary and unnecessary to set profile block"); + return; + } + provisionInfo.profileBlockLength = hapProfileBlock.GetCapacity(); + SIGNATURE_TOOLS_LOGD("profile block data length is %d", provisionInfo.profileBlockLength); + if (provisionInfo.profileBlockLength == 0) { + SIGNATURE_TOOLS_LOGE("invalid profile block"); + return; + } + provisionInfo.profileBlock = std::make_unique(provisionInfo.profileBlockLength); + + if (memcpy_s(provisionInfo.profileBlock.get(), provisionInfo.profileBlockLength, + hapProfileBlock.GetBufferPtr(), + provisionInfo.profileBlockLength) != 0) { + SIGNATURE_TOOLS_LOGE("memcpy failed"); + } +} + +bool VerifyHap::VerifyProfileInfo(const Pkcs7Context& pkcs7Context, const Pkcs7Context& profileContext, + ProfileInfo& provisionInfo) +{ + std::string& certInProfile = provisionInfo.bundleInfo.developmentCertificate; + if (provisionInfo.type == ProvisionType::RELEASE) { + if (!IsAppDistributedTypeAllowInstall(provisionInfo.distributionType, provisionInfo)) { + SIGNATURE_TOOLS_LOGE("untrusted source app with release profile distributionType: %d", + static_cast(provisionInfo.distributionType)); + return false; + } + certInProfile = provisionInfo.bundleInfo.distributionCertificate; + SIGNATURE_TOOLS_LOGD("allow install app with release profile distributionType: %d", + static_cast(provisionInfo.distributionType)); + } + SIGNATURE_TOOLS_LOGD("provisionInfo.type: %d", static_cast(provisionInfo.type)); + return true; +} + +bool VerifyHap::IsAppDistributedTypeAllowInstall(const AppDistType& type, + const ProfileInfo& provisionInfo) const +{ + switch (type) { + case AppDistType::NONE_TYPE: + return false; + case AppDistType::APP_GALLERY: + case AppDistType::ENTERPRISE: + case AppDistType::ENTERPRISE_NORMAL: + case AppDistType::ENTERPRISE_MDM: + case AppDistType::OS_INTEGRATION: + case AppDistType::CROWDTESTING: + return true; + default: + return false; + } +} + +bool VerifyHap::ParseAndVerifyProfileIfNeed(const std::string& profile, + ProfileInfo& provisionInfo, bool isCallParseAndVerify) +{ + if (isCallParseAndVerify) { + return isCallParseAndVerify; + } + AppProvisionVerifyResult profileRet = ParseAndVerify(profile, provisionInfo); + if (profileRet != PROVISION_OK) { + SIGNATURE_TOOLS_LOGE("profile parse failed, error: %d", static_cast(profileRet)); + return false; + } + return true; +} + +bool VerifyHap::GetDigestAndAlgorithm(Pkcs7Context& digest) +{ + /* + * contentinfo format: + * int: version + * int: block number + * digest blocks: + * each digest block format: + * int: length of sizeof(digestblock) - 4 + * int: Algorithm ID + * int: length of digest + * byte[]: digest + */ + /* length of sizeof(digestblock - 4) */ + int32_t digestBlockLen; + if (!digest.content.GetInt32(DIGEST_BLOCK_LEN_OFFSET, digestBlockLen)) { + SIGNATURE_TOOLS_LOGE("get digestBlockLen failed"); + return false; + } + /* Algorithm ID */ + if (!digest.content.GetInt32(DIGEST_ALGORITHM_OFFSET, digest.digestAlgorithm)) { + SIGNATURE_TOOLS_LOGE("get digestAlgorithm failed"); + return false; + } + /* length of digest */ + int32_t digestlen; + if (!digest.content.GetInt32(DIGEST_LEN_OFFSET, digestlen)) { + SIGNATURE_TOOLS_LOGE("get digestlen failed"); + return false; + } + int32_t sum = sizeof(digestlen) + sizeof(digest.digestAlgorithm) + digestlen; + if (sum != digestBlockLen) { + SIGNATURE_TOOLS_LOGE("digestBlockLen: %d is not equal to sum: %d", + digestBlockLen, sum); + return false; + } + /* set position to the digest start point */ + digest.content.SetPosition(DIGEST_OFFSET_IN_CONTENT); + /* set limit to the digest end point */ + digest.content.SetLimit(DIGEST_OFFSET_IN_CONTENT + digestlen); + digest.content.Slice(); + return true; +} + +void VerifyHap::SetOrganization(ProfileInfo& provisionInfo) +{ + std::string& certInProfile = provisionInfo.bundleInfo.distributionCertificate; + if (provisionInfo.bundleInfo.distributionCertificate.empty()) { + SIGNATURE_TOOLS_LOGE("distributionCertificate is empty"); + return; + } + std::string organization; + if (!VerifyCertOpensslUtils::GetOrganizationFromPemCert(certInProfile, organization)) { + SIGNATURE_TOOLS_LOGE("Generate organization from pem certificate failed"); + return; + } + provisionInfo.organization = organization; +} + +int32_t VerifyHap::VerifyElfProfile(std::vector& profileData, HapVerifyResult& hapVerifyV1Result, + Options* options, Pkcs7Context& pkcs7Context) +{ + const unsigned char* pkcs7Block = reinterpret_cast(profileData.data()); + uint32_t pkcs7Len = static_cast(profileData.size()); + if (!VerifyHapOpensslUtils::ParsePkcs7Package(pkcs7Block, pkcs7Len, pkcs7Context)) { + SIGNATURE_TOOLS_LOGE("parse pkcs7 failed"); + return VERIFY_APP_PKCS7_FAIL; + } + if (!VerifyHapOpensslUtils::GetCertChains(pkcs7Context.p7, pkcs7Context)) { + SIGNATURE_TOOLS_LOGE("GetCertChains from pkcs7 failed"); + return VERIFY_APP_PKCS7_FAIL; + } + if (!VerifyHapOpensslUtils::VerifyPkcs7(pkcs7Context)) { + SIGNATURE_TOOLS_LOGE("verify signature failed"); + return VERIFY_APP_PKCS7_FAIL; + } + std::vector publicKeys; + if (!VerifyHapOpensslUtils::GetPublickeys(pkcs7Context.certChains[0], publicKeys)) { + SIGNATURE_TOOLS_LOGE("Get publicKeys failed"); + return GET_PUBLICKEY_FAIL; + } + hapVerifyV1Result.SetPublicKey(publicKeys); + std::vector certSignatures; + if (!VerifyHapOpensslUtils::GetSignatures(pkcs7Context.certChains[0], certSignatures)) { + SIGNATURE_TOOLS_LOGE("Get sianatures failed"); + return GET_SIGNATURE_FAIL; + } + hapVerifyV1Result.SetSignature(certSignatures); + return VERIFY_SUCCESS; +} + +int32_t VerifyHap::WriteVerifyOutput(Pkcs7Context& pkcs7Context, std::vector profile, Options* options) +{ + if (pkcs7Context.certChains.size() > 0) { + bool flag = VerifyHap::HapOutPutCertChain(pkcs7Context.certChains[0], + options->GetString(Options::OUT_CERT_CHAIN)); + if (!flag) { + SIGNATURE_TOOLS_LOGE("out put cert chain failed"); + return OUT_PUT_FILE_FAIL; + } + } + if (pkcs7Context.p7 == nullptr) { + std::string p7bContent(profile.begin(), profile.end()); + bool writeFlag = FileUtils::Write(p7bContent, options->GetString(Options::OUT_PROFILE)) < 0; + if (writeFlag) { + SIGNATURE_TOOLS_LOGE("p7b write to file falied!\n"); + return OUT_PUT_FILE_FAIL; + } + return VERIFY_SUCCESS; + } + bool pkcs7flag = VerifyHap::HapOutPutPkcs7(pkcs7Context.p7, options->GetString(Options::OUT_PROFILE)); + if (!pkcs7flag) { + SIGNATURE_TOOLS_LOGE("out put p7b failed"); + return OUT_PUT_FILE_FAIL; + } + return VERIFY_SUCCESS; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/main.cpp b/hapsigntool_cpp/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f18964f72b137cc5b81897b58107540ab9f5f99b --- /dev/null +++ b/hapsigntool_cpp/main.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024-2024 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/hapsigntool_cpp/profile/include/.gitignore b/hapsigntool_cpp/profile/include/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..259148fa18f9fb7ef58563f4ff15fc7b172339fb --- /dev/null +++ b/hapsigntool_cpp/profile/include/.gitignore @@ -0,0 +1,32 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/hapsigntool_cpp/profile/include/pkcs7_data.h b/hapsigntool_cpp/profile/include/pkcs7_data.h new file mode 100644 index 0000000000000000000000000000000000000000..2e5128e1e51566f91d9c32e67ffdbdffbae14db5 --- /dev/null +++ b/hapsigntool_cpp/profile/include/pkcs7_data.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2024-2024 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; + } +}; + +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, 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, 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/hapsigntool_cpp/profile/include/profile_info.h b/hapsigntool_cpp/profile/include/profile_info.h new file mode 100644 index 0000000000000000000000000000000000000000..e4b37a9bd6d639e616322d7d4cb01a7c93f3af44 --- /dev/null +++ b/hapsigntool_cpp/profile/include/profile_info.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2024-2024 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 = 0, + RELEASE = 1, + DEBUG = 2 +}; +enum AppDistType { + NONE_TYPE = 0, + APP_GALLERY = 1, + ENTERPRISE = 2, + OS_INTEGRATION = 3, + CROWDTESTING = 4, + ENTERPRISE_NORMAL = 5, + ENTERPRISE_MDM = 6, +}; +struct BundleInfo { + std::string developerId; + std::string developmentCertificate; + std::string distributionCertificate; + std::string bundleName; + std::string apl; + std::string appFeature; + std::string appIdentifier; + std::vector dataGroupIds; +}; +struct Acls { + std::vector allowedAcls; +}; +struct Permissions { + std::vector restrictedPermissions; + std::vector restrictedCapabilities; +}; +struct DebugInfo { + std::string deviceIdType; + std::vector deviceIds; +}; +struct Validity { + int64_t notBefore = 0; + int64_t notAfter = 0; +}; +struct Metadata { + std::string name; + std::string value; + std::string resource; +}; +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 versionName; + std::string uuid; + ProvisionType type = NONE_PROVISION_TYPE; + AppDistType distributionType = NONE_TYPE; + BundleInfo bundleInfo; + Acls acls; + Permissions permissions; + DebugInfo debugInfo; + std::string issuer; + std::string appId; + std::string fingerprint; + std::vector appPrivilegeCapabilities; + Validity validity; + std::vector metadatas; + int32_t profileBlockLength = 0; + std::unique_ptr profileBlock; + std::string appServiceCapabilities; + std::string organization; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_PROFILE_INFO_H diff --git a/hapsigntool_cpp/profile/include/profile_sign_tool.h b/hapsigntool_cpp/profile/include/profile_sign_tool.h new file mode 100644 index 0000000000000000000000000000000000000000..8c5b870fba9da1db2109a23470cc793e17ce4408 --- /dev/null +++ b/hapsigntool_cpp/profile/include/profile_sign_tool.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024-2024 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, + 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/hapsigntool_cpp/profile/include/profile_verify.h b/hapsigntool_cpp/profile/include/profile_verify.h new file mode 100644 index 0000000000000000000000000000000000000000..52416967e5d85d9834de1c02c44306359f87eaf6 --- /dev/null +++ b/hapsigntool_cpp/profile/include/profile_verify.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2024-2024 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); +DLL_EXPORT void SetRdDevice(bool isRdDevice); +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_PROFILE_VERIFY_H diff --git a/hapsigntool_cpp/profile/include/profile_verify_utils.h b/hapsigntool_cpp/profile/include/profile_verify_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..1eef463e03c2283d7f4c30f29aa14230b62e1af4 --- /dev/null +++ b/hapsigntool_cpp/profile/include/profile_verify_utils.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024-2024 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_UTILS_H +#define SIGNATRUETOOLS_PROFILE_VERIFY_UTILS_H + +#include + +#include "export_define.h" +#include "byte_buffer.h" +#include "pkcs7_context.h" + +namespace OHOS { +namespace SignatureTools { +class ProfileVerifyUtils { +public: + DLL_EXPORT static bool ParseProfile(Pkcs7Context& profilePkcs7Context, + const Pkcs7Context& pkcs7Context, + const ByteBuffer& pkcs7ProfileBlock, + std::string& profile); + DLL_EXPORT static bool VerifyProfile(Pkcs7Context& pkcs7Context); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_PROFILE_VERIFY_UTILS_H diff --git a/hapsigntool_cpp/profile/signature_tools_profile.gni b/hapsigntool_cpp/profile/signature_tools_profile.gni new file mode 100644 index 0000000000000000000000000000000000000000..63fa958314a543efd2d432eb961d2f5821eac9e0 --- /dev/null +++ b/hapsigntool_cpp/profile/signature_tools_profile.gni @@ -0,0 +1,23 @@ +# Copyright (c) 2024 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", + "${signature_tools_profile}/src/profile_verify_utils.cpp", +] diff --git a/hapsigntool_cpp/profile/src/pkcs7_data.cpp b/hapsigntool_cpp/profile/src/pkcs7_data.cpp new file mode 100644 index 0000000000000000000000000000000000000000..08eb9cfbf7b175f4676431c607382bba82a6c2f8 --- /dev/null +++ b/hapsigntool_cpp/profile/src/pkcs7_data.cpp @@ -0,0 +1,820 @@ +/* + * Copyright (c) 2024-2024 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, 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!"); + BIO_free_all(oriBio); + 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, 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((ASN1_VALUE*)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, (unsigned char*)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/hapsigntool_cpp/profile/src/profile_info.cpp b/hapsigntool_cpp/profile/src/profile_info.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3dcf3cf3ee31b3397856d4e3b6166918ae3b05a3 --- /dev/null +++ b/hapsigntool_cpp/profile/src/profile_info.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024-2024 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 "signature_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& info) +{ + *this = info; +} +ProfileInfo& ProfileInfo::operator=(const ProfileInfo& info) +{ + if (this == &info) { + return *this; + } + this->versionCode = info.versionCode; + this->versionName = info.versionName; + this->uuid = info.uuid; + this->type = info.type; + this->distributionType = info.distributionType; + this->bundleInfo = info.bundleInfo; + this->acls = info.acls; + this->permissions = info.permissions; + this->debugInfo = info.debugInfo; + this->issuer = info.issuer; + this->appId = info.appId; + this->fingerprint = info.fingerprint; + this->appPrivilegeCapabilities = info.appPrivilegeCapabilities; + this->validity = info.validity; + this->metadatas = info.metadatas; + this->profileBlockLength = info.profileBlockLength; + (this->profileBlock).reset(nullptr); + if (info.profileBlockLength != 0 && info.profileBlock != nullptr) { + this->profileBlock = std::make_unique(info.profileBlockLength); + unsigned char* profileBlockData = (this->profileBlock).get(); + unsigned char* originalProfile = info.profileBlock.get(); + if (profileBlockData == nullptr) { + return *this; + } + std::copy(originalProfile, originalProfile + info.profileBlockLength, profileBlockData); + } + this->appServiceCapabilities = info.appServiceCapabilities; + this->organization = info.organization; + return *this; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/profile/src/profile_sign_tool.cpp b/hapsigntool_cpp/profile/src/profile_sign_tool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..044538336a51c61354d347b6f4906316665a887f --- /dev/null +++ b/hapsigntool_cpp/profile/src/profile_sign_tool.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024-2024 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(); + int result = RET_OK; + if (signerFactory == NULL) { + PrintErrorNumberMsg("INVALIDPARAM_ERROR", INVALIDPARAM_ERROR, + "signerFactory is NULL, create signerFactor failed"); + return INVALIDPARAM_ERROR; + } + 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 + result = SignProfile(content, signer, sigAlg, ret) < 0; + if (result < 0) { + SIGNATURE_TOOLS_LOGE("generate p7b failed"); + return SIGN_ERROR; + } + PKCS7Data p7Data; + result = p7Data.Parse(ret); + if (result < 0) { + SIGNATURE_TOOLS_LOGE("parse p7b failed"); + return PARSE_ERROR; + } + result = p7Data.Verify(); + if (result < 0) { + SIGNATURE_TOOLS_LOGE("verify p7b failed"); + return VERIFY_ERROR; + } + return result; +} +/** +* @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, 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; + } + return result; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/profile/src/profile_verify.cpp b/hapsigntool_cpp/profile/src/profile_verify.cpp new file mode 100644 index 0000000000000000000000000000000000000000..02071679572e3144b7cfd1524fc07ab924f47419 --- /dev/null +++ b/hapsigntool_cpp/profile/src/profile_verify.cpp @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2024-2024 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 "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 = ".*"; +const int32_t VERSION_CODE_TWO = 2; +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} +}; +static bool g_isRdDevice = false; +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", PROVISION_INVALID, errMsg); + return PROVISION_INVALID; + } + return PROVISION_OK; +} + +AppProvisionVerifyResult ReturnIfIntIsNonPositive(int num, const std::string& errMsg) +{ + if (num <= 0) { + PrintErrorNumberMsg("PROVISION_INVALID", PROVISION_INVALID, errMsg); + return PROVISION_INVALID; + } + return PROVISION_OK; +} + +static AppProvisionVerifyResult CheckProfileValidType(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", PROVISION_INVALID, "Require build type must be debug or release"); + return PROVISION_INVALID; + } + return PROVISION_OK; +} + +AppProvisionVerifyResult ParseProvision(const string& appProvision, ProfileInfo& info) +{ + AppProvisionVerifyResult result = PROVISION_OK; + if (ParseProfile(appProvision, info) != PROVISION_OK) { + return PROVISION_INVALID; + } + result = ReturnIfIntIsNonPositive(info.versionCode, "Tag version code is empty."); + if (result != PROVISION_OK) { + return PROVISION_INVALID; + } + result = ReturnIfStringIsEmpty(info.versionName, "Tag version name is empty."); + if (result != PROVISION_OK) { + return PROVISION_INVALID; + } + result = ReturnIfStringIsEmpty(info.uuid, "Tag uuid is empty."); + if (result != PROVISION_OK) { + return PROVISION_INVALID; + } + result = ReturnIfStringIsEmpty(info.bundleInfo.developerId, "Tag developer-id is empty."); + if (result != PROVISION_OK) { + return PROVISION_INVALID; + } + + if (CheckProfileValidType(info) != PROVISION_OK) { + return PROVISION_INVALID; + } + + if (ReturnIfStringIsEmpty(info.bundleInfo.bundleName, "Tag bundle-name is empty.") != PROVISION_OK) { + return PROVISION_INVALID; + } + if (info.bundleInfo.bundleName == GENERIC_BUNDLE_NAME) { + SIGNATURE_TOOLS_LOGD("generic package name: %s, is used.", + GENERIC_BUNDLE_NAME.c_str()); + } + if (info.versionCode >= VERSION_CODE_TWO) { + if (ReturnIfStringIsEmpty(info.bundleInfo.apl, "Tag apl is empty.") != PROVISION_OK) { + return PROVISION_INVALID; + } + } + if (ReturnIfStringIsEmpty(info.bundleInfo.appFeature, "Tag app-feature is empty.") != PROVISION_OK) { + return PROVISION_INVALID; + } + return PROVISION_OK; +} + +void SetRdDevice(bool isRdDevice) +{ + g_isRdDevice = isRdDevice; +} +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", PROVISION_INVALID, 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/hapsigntool_cpp/profile/src/profile_verify_utils.cpp b/hapsigntool_cpp/profile/src/profile_verify_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7baea995a8348216ae2dad01a2e54ccfce6295bb --- /dev/null +++ b/hapsigntool_cpp/profile/src/profile_verify_utils.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024-2024 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_verify_utils.h" +#include "signature_tools_log.h" +#include "matching_result.h" +#include "verify_cert_openssl_utils.h" +#include "hap_signer_block_utils.h" +#include "verify_hap_openssl_utils.h" + +namespace OHOS { +namespace SignatureTools { + +bool ProfileVerifyUtils::ParseProfile(Pkcs7Context& profilePkcs7Context, + const Pkcs7Context& hapPkcs7Context, + const ByteBuffer& pkcs7ProfileBlock, std::string& profile) +{ + if (hapPkcs7Context.matchResult.matchState == MATCH_WITH_SIGN && + hapPkcs7Context.matchResult.source == APP_GALLARY) { + profile = std::string(pkcs7ProfileBlock.GetBufferPtr(), pkcs7ProfileBlock.GetCapacity()); + SIGNATURE_TOOLS_LOGD("hap include unsigned provision"); + return true; + } + const unsigned char* pkcs7Block = reinterpret_cast( + pkcs7ProfileBlock.GetBufferPtr()); + uint32_t pkcs7Len = static_cast(pkcs7ProfileBlock.GetCapacity()); + if (!VerifyHapOpensslUtils::ParsePkcs7Package(pkcs7Block, pkcs7Len, profilePkcs7Context)) { + SIGNATURE_TOOLS_LOGE("parse pkcs7 failed"); + return false; + } + profile = std::string(profilePkcs7Context.content.GetBufferPtr(), + profilePkcs7Context.content.GetCapacity()); + return true; +} +bool ProfileVerifyUtils::VerifyProfile(Pkcs7Context& pkcs7Context) +{ + if (!VerifyHapOpensslUtils::GetCertChains(pkcs7Context.p7, pkcs7Context)) { + SIGNATURE_TOOLS_LOGE("GetCertChains from pkcs7 failed"); + return false; + } + if (!VerifyHapOpensslUtils::VerifyPkcs7(pkcs7Context)) { + SIGNATURE_TOOLS_LOGE("verify profile signature failed"); + return false; + } + return true; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/signature_tools.gni b/hapsigntool_cpp/signature_tools.gni new file mode 100644 index 0000000000000000000000000000000000000000..c4b28f8560da97e26d9466a02b6b9799168eec2d --- /dev/null +++ b/hapsigntool_cpp/signature_tools.gni @@ -0,0 +1,25 @@ +# Copyright (c) 2024 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/hapsigntool_cpp" +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_zip = "${signature_tools_root_path}/zip" +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 = "${signature_tools_root_path}/test" diff --git a/hapsigntool_cpp/signer/include/local_signer.h b/hapsigntool_cpp/signer/include/local_signer.h new file mode 100644 index 0000000000000000000000000000000000000000..97bc60d70db2ec8b95ea8f92e571dbb221f283a5 --- /dev/null +++ b/hapsigntool_cpp/signer/include/local_signer.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024-2024 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/hapsigntool_cpp/signer/include/signer.h b/hapsigntool_cpp/signer/include/signer.h new file mode 100644 index 0000000000000000000000000000000000000000..a0a7ac4e4faada411f8e7c6ae75072c40f06d160 --- /dev/null +++ b/hapsigntool_cpp/signer/include/signer.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024-2024 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/hapsigntool_cpp/signer/include/signer_factory.h b/hapsigntool_cpp/signer/include/signer_factory.h new file mode 100644 index 0000000000000000000000000000000000000000..01604bb8f3744a2c663b1856df65cec370b1aaa7 --- /dev/null +++ b/hapsigntool_cpp/signer/include/signer_factory.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024-2024 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" +#include "remote_sign_provider.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/hapsigntool_cpp/signer/src/local_signer.cpp b/hapsigntool_cpp/signer/src/local_signer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..30fc7f45eac23a199d387a8c11a97a85753a5c9f --- /dev/null +++ b/hapsigntool_cpp/signer/src/local_signer.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2024-2024 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/hapsigntool_cpp/signer/src/signer_factory.cpp b/hapsigntool_cpp/signer/src/signer_factory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b8e57e29d339d483d4f9db7917b8cba5c4502e6b --- /dev/null +++ b/hapsigntool_cpp/signer/src/signer_factory.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2024-2024 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" + +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); + if (signer == NULL) { + SIGNATURE_TOOLS_LOGE("signer is NULL, create LocalSigner failed"); + EVP_PKEY_free(keyPair); + sk_X509_pop_free(certs, X509_free); + return NULL; + } + 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); + std::string userPwd = adapter.GetOptions()->GetChars(ParamConstants::PARAM_REMOTE_USERPWD); + + // open so + RemoteSignProvider::handle = dlopen(signerPlugin.c_str(), RTLD_NOW | RTLD_GLOBAL); + if (!RemoteSignProvider::handle) { + PrintErrorNumberMsg("LoadRemoteSigner", RET_FAILED, dlerror()); + return nullptr; + } + + // clear previous error + dlerror(); + + // get "Create" function + RemoteSignerCreator remoteSignerCreator = (RemoteSignerCreator)dlsym(RemoteSignProvider::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.c_str(), userPwd.size()}; + + Signer* signer = remoteSignerCreator(keyAliasType, signServerType, onlineAuthModeType, usernameType, userPwdType); + + userPwd.clear(); + + std::shared_ptr remoteSigner(signer); + + return remoteSigner; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/utils/include/byte_array_utils.h b/hapsigntool_cpp/utils/include/byte_array_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..8aaa5e846363d1dfd32f3c5743d8b354dfba9112 --- /dev/null +++ b/hapsigntool_cpp/utils/include/byte_array_utils.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024-2024 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_BYTEARRAYTUTILS_EXCEPTION_H +#define SIGNATRUETOOLS_BYTEARRAYTUTILS_EXCEPTION_H + +#include +#include + +#include "memory.h" + +namespace OHOS { +namespace SignatureTools { +class ByteArrayUtils { +public: + static int InsertIntToByteArray(std::vector& desByte, int index, int num); + static int InsertShortToByteArray(std::vector& desByte, size_t desByteLen, int index, short num); + static int InsertByteToByteArray(std::vector& des, int start, std::vector src, int srcLen); + static int InsertCharToByteArray(std::vector& des, int start, std::string src); + +private: + static constexpr int BIT_SIZE = 8; + static constexpr int DOUBLE_BIT_SIZE = 16; + static constexpr int TRIPLE_BIT_SIZE = 24; + static constexpr int HALF_INTEGER_BYTES = 2; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_BYTEARRAYTUTILS_EXCEPTION_H \ No newline at end of file diff --git a/hapsigntool_cpp/utils/include/cert_dn_utils.h b/hapsigntool_cpp/utils/include/cert_dn_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..02a55aa79dda92c9461b5a63eba57878eb351719 --- /dev/null +++ b/hapsigntool_cpp/utils/include/cert_dn_utils.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024-2024 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_CERTUTILS_H +#define SIGNATRUETOOLS_CERTUTILS_H + +#include +#include +#include +#include + +#include "openssl/ossl_typ.h" +#include "openssl/x509.h" +#include "openssl/x509v3.h" +#include "string_utils.h" +#include "signature_tools_errno.h" +#include "signature_tools_log.h" + +using std::pair; +using std::istringstream; +using std::getline; + +namespace OHOS { +namespace SignatureTools { +/** +* buildDN +* +* @param nameString nameString +* @return X500Name +*/ +X509_NAME* BuildDN(std::string nameString, X509_REQ* req); +/** +* To verify the format of subject or issuer. +* Refer to X509_NAMEStyle.fromstring(). +* +* @param nameString subject or issuer +*/ +int g_checkDn(std::string nameString, std::vector>& pairs); +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_CERTUTILS_H \ No newline at end of file diff --git a/hapsigntool_cpp/utils/include/file_utils.h b/hapsigntool_cpp/utils/include/file_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..565329f0287f1462c3035ea9a298aa528b2e27dd --- /dev/null +++ b/hapsigntool_cpp/utils/include/file_utils.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2024-2024 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 "thread_pool.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); + /** + * 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 bool AppendWriteFileByOffsetToFile(std::ifstream& input, std::ofstream& out, size_t offset, size_t size); + static bool AppendWriteFileToFile(const std::string& inputFile, const std::string& outputFile); + static bool AppendWriteByteToFile(const std::string& bytes, const std::string& outputFile); + + static int WriteInputToOutPut(std::ifstream& input, std::ofstream& output, size_t length); + static bool WriteInputToOutPut(const std::string& input, const std::string& output); + static bool IsSpaceEnough(const std::string& filePath, const int64_t requiredSpace); + /** +* Write byte array data to output file. +* +* @param bytes byte array data. +* @param outFile output file path. +* @return true, if write successfully. +*/ + static bool WriteByteToOutFile(const std::string& bytes, const std::string& outFile); + /** +* Write byte array data to output file. +* +* @param bytes byte array data. +* @param outFile output file path. +* @return true, if write successfully. +*/ + static bool WriteByteToOutFile(const std::string& bytes, std::ofstream& outFile); + static bool WriteByteToOutFile(const std::vector& bytes, std::ofstream& outFile); + /** + * 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); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_FILE_UTILS_H \ No newline at end of file diff --git a/hapsigntool_cpp/utils/include/hap_signer_block_utils.h b/hapsigntool_cpp/utils/include/hap_signer_block_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..c45ba852bfc2efe55442d395e493523c91e8ff37 --- /dev/null +++ b/hapsigntool_cpp/utils/include/hap_signer_block_utils.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2024-2024 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_SIGNING_BLOCK_UTILS_H +#define SIGNATRUETOOLS_SIGNING_BLOCK_UTILS_H + +#include + +#include "data_source.h" +#include "export_define.h" +#include "byte_buffer.h" +#include "random_access_file.h" +#include "hap_verify_result.h" +#include "digest_parameter.h" +#include "pkcs7_context.h" +#include "signature_info.h" + +namespace OHOS { +namespace SignatureTools { + +constexpr int32_t ZIP_CHUNK_DIGEST_PRIFIX_LEN = 5; + +enum HapBlobType { + HAP_SIGN_BLOB = 0x20000000, + PROOF_ROTATION_BLOB = 0x20000001, + PROFILE_BLOB = 0x20000002, + PROPERTY_BLOB = 0x20000003, +}; + +struct HapSignBlockHead { + int32_t version = 0; + int32_t blockCount = 0; + int64_t hapSignBlockSize; + int64_t hapSignBlockMagicLo; + int64_t hapSignBlockMagicHi; +}; + +struct HapSubSignBlockHead { + uint32_t type = 0; + uint32_t length = 0; + uint32_t offset = 0; +}; + +class HapSignerBlockUtils { +public: + DLL_EXPORT static const int64_t HAP_SIG_BLOCK_MAGIC_HIGH_OLD; + DLL_EXPORT static const int64_t HAP_SIG_BLOCK_MAGIC_LOW_OLD; + DLL_EXPORT static const int64_t HAP_SIG_BLOCK_MAGIC_HIGH; + DLL_EXPORT static const int64_t HAP_SIG_BLOCK_MAGIC_LOW; + DLL_EXPORT static const int32_t ZIP_HEAD_OF_SIGNING_BLOCK_LENGTH; + DLL_EXPORT static const int32_t ZIP_EOCD_SEGMENT_FLAG; + static const int64_t CHUNK_SIZE; + static const int32_t HAP_SIG_BLOCK_MIN_SIZE; + static const int32_t ZIP_EOCD_SEG_MIN_SIZE; + static const int32_t ZIP_EOCD_COMMENT_LENGTH_OFFSET; + static const int32_t ZIP_CD_OFFSET_IN_EOCD; + static const int32_t ZIP_CD_SIZE_OFFSET_IN_EOCD; + static const int32_t ZIP_BLOCKS_NUM_NEED_DIGEST; + static const char ZIP_FIRST_LEVEL_CHUNK_PREFIX; + static const char ZIP_SECOND_LEVEL_CHUNK_PREFIX; + /* the specifications of hap sign block */ + static constexpr int64_t MAX_HAP_SIGN_BLOCK_SIZE = 1024 * 1024 * 1024LL; // 1024MB + static constexpr int32_t MAX_BLOCK_COUNT = 10; + static constexpr int32_t VERSION_FOR_NEW_MAGIC_NUM = 3; + static constexpr int32_t TEST_FILE_BLOCK_LENGTH = 50; + static constexpr int32_t TEST_FILE_BLOCK_COUNT = 3; + + HapSignerBlockUtils() = delete; + DLL_EXPORT static bool FindHapSignature(RandomAccessFile& hapFile, SignatureInfo& signInfo); + DLL_EXPORT static bool GetOptionalBlockIndex(std::vector& optionBlocks, + int32_t type, int& index); + DLL_EXPORT static bool VerifyHapIntegrity(Pkcs7Context& digestInfo, RandomAccessFile& hapFile, + SignatureInfo& signInfo); + DLL_EXPORT static int64_t CreatTestZipFile(const std::string& pathFile, SignatureInfo& signInfo); + + DLL_EXPORT static bool FindEocdInHap(RandomAccessFile& hapFile, std::pair& eocd); + DLL_EXPORT static bool FindEocdInHap(RandomAccessFile& hapFile, unsigned short maxCommentSize, + std::pair& eocd); + DLL_EXPORT static bool FindEocdInSearchBuffer(ByteBuffer& zipContents, int& offset); + DLL_EXPORT static bool GetCentralDirectoryOffset(ByteBuffer& eocd, int64_t eocdOffset, + int64_t& centralDirectoryOffset); + DLL_EXPORT static bool GetCentralDirectorySize(ByteBuffer& eocd, long& centralDirectorySize); + static bool FindHapSigningBlock(RandomAccessFile& hapFile, int64_t centralDirOffset, + SignatureInfo& signInfo); + static bool FindHapSubSigningBlock(RandomAccessFile& hapFile, + int32_t blockCount, + int64_t blockArrayLen, + int64_t hapSignBlockOffset, + SignatureInfo& signInfo); + DLL_EXPORT static bool ClassifyHapSubSigningBlock(SignatureInfo& signInfo, + const ByteBuffer& subBlock, uint32_t type); + DLL_EXPORT static bool SetUnsignedInt32(ByteBuffer& buffer, int32_t offset, int64_t value); + DLL_EXPORT static bool ComputeDigestsWithOptionalBlock(const DigestParameter& digestParam, + const std::vector& optionalBlocks, + const ByteBuffer& chunkDigest, + ByteBuffer& finalDigest); + static bool ComputeDigestsForEachChunk(const DigestParameter& digestParam, DataSource* contents[], + int32_t len, ByteBuffer& result); + static int32_t GetChunkCount(int64_t inputSize, int64_t chunkSize); + static bool InitDigestPrefix(const DigestParameter& digestParam, + unsigned char(&chunkContentPrefix)[ZIP_CHUNK_DIGEST_PRIFIX_LEN], + int32_t chunkLen); + DLL_EXPORT static DigestParameter GetDigestParameter(int32_t nId); + DLL_EXPORT static bool GetSumOfChunkDigestLen(DataSource* contents[], int32_t len, int32_t chunkDigestLen, + int& chunkCount, int& sumOfChunkDigestLen); + static bool ParseSignBlockHead(HapSignBlockHead& hapSignBlockHead, ByteBuffer& hapBlockHead); + static bool ParseSubSignBlockHead(HapSubSignBlockHead& subSignBlockHead, ByteBuffer& hapBlockHead); + static bool CheckSignBlockHead(const HapSignBlockHead& hapSignBlockHead); + static void CreateHapSubSignBlockHead(HapSubSignBlockHead& signBlob, HapSubSignBlockHead& profileBlob, + HapSubSignBlockHead& propertyBlob); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // HAP_SIGNING_BLOCK_UTILS_H diff --git a/hapsigntool_cpp/utils/include/hash_utils.h b/hapsigntool_cpp/utils/include/hash_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..bc57f65d362a1b470ec5a063cd8253d9e9e9b3b4 --- /dev/null +++ b/hapsigntool_cpp/utils/include/hash_utils.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024-2024 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/hapsigntool_cpp/utils/include/key_store_helper.h b/hapsigntool_cpp/utils/include/key_store_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..ab66558613d970737acf94a5ea53995c6bb0451c --- /dev/null +++ b/hapsigntool_cpp/utils/include/key_store_helper.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2024-2024 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)* bags, 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)* bags, + 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/hapsigntool_cpp/utils/include/signature_info.h b/hapsigntool_cpp/utils/include/signature_info.h new file mode 100644 index 0000000000000000000000000000000000000000..d8dd10b5d5e8b8a2704a7554d84d76c53cb95c8d --- /dev/null +++ b/hapsigntool_cpp/utils/include/signature_info.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2024-2024 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" +#include "hap_verify_result.h" + +namespace OHOS { +namespace SignatureTools { +struct SignatureInfo { + ByteBuffer hapSignatureBlock; + int64_t hapSigningBlockOffset; + int64_t hapCentralDirOffset; + int64_t hapEocdOffset; + ByteBuffer hapEocd; + std::vector optionBlocks; + int32_t version = 0; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // HAP_SIGNATURE_INFO_H diff --git a/hapsigntool_cpp/utils/include/signature_tools_errno.h b/hapsigntool_cpp/utils/include/signature_tools_errno.h new file mode 100644 index 0000000000000000000000000000000000000000..f933ca064f7a76f7eabad7c1625f96b14abd0389 --- /dev/null +++ b/hapsigntool_cpp/utils/include/signature_tools_errno.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2024-2024 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; + +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATURETOOLS_INDUSTRIAL_BUS_ERRNO_H \ No newline at end of file diff --git a/hapsigntool_cpp/utils/include/signature_tools_log.h b/hapsigntool_cpp/utils/include/signature_tools_log.h new file mode 100644 index 0000000000000000000000000000000000000000..f919423bded8dd58bedec4bd95c4f9ca353222c4 --- /dev/null +++ b/hapsigntool_cpp/utils/include/signature_tools_log.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2024-2024 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 "signature_tools_errno.h" + +namespace OHOS { +namespace SignatureTools { + + +#define SIGNATURE_LOG(level, fmt, ...) \ + printf("[%s] [%s] [%s] [%d] " fmt "\n", level, __FILE__, __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__) + + +/* +* 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) +{ + time_t now = time(0); + if (!now) return; + char timebuffer[100] = { 0 }; + struct tm* time = localtime(&now); + if (!time && !strftime(timebuffer, sizeof(timebuffer), "%m-%d %H:%M:%S", time)) return; + std::cerr << timebuffer << " 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) +{ + time_t now = time(0); + if (!now) { + return; + } + char timebuffer[100] = { 0 }; + struct tm* time = localtime(&now); + if (!time && !strftime(timebuffer, sizeof(timebuffer), "%m-%d %H:%M:%S", time)) { + return; + } + std::cout << timebuffer << " INFO - " << message << std::endl; +} + +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATURETOOLS_SIGNATRUE_TOOLS_LOG_H \ No newline at end of file diff --git a/hapsigntool_cpp/utils/include/string_utils.h b/hapsigntool_cpp/utils/include/string_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..ab8a253b38bf4eecb17b29e4493ec1481ff677bf --- /dev/null +++ b/hapsigntool_cpp/utils/include/string_utils.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024-2024 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(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); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_STRINGUTILS_H \ No newline at end of file diff --git a/hapsigntool_cpp/utils/include/verify_cert_openssl_utils.h b/hapsigntool_cpp/utils/include/verify_cert_openssl_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..4e07b83befb90303794d4929afc26c881d70ea23 --- /dev/null +++ b/hapsigntool_cpp/utils/include/verify_cert_openssl_utils.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024-2024 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 X509* GetX509CertFromPemString(const std::string& pemString); + DLL_EXPORT static X509* GetX509CertFromBase64String(const std::string& base64String); + DLL_EXPORT static X509_CRL* GetX509CrlFromDerBuffer(const ByteBuffer& crlBuffer, + int32_t offset, int32_t len); + 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 GetSubjectFromX509(const X509* cert, std::string& subject); + DLL_EXPORT static bool GetIssuerFromX509(const X509* cert, std::string& issuer); + DLL_EXPORT static bool GetSerialNumberFromX509(const X509* cert, int64_t& certNumber); + DLL_EXPORT static bool GetIssuerFromX509Crl(const X509_CRL* crl, std::string& issuer); + DLL_EXPORT static bool VerifyCertChainPeriodOfValidity(CertChain& certsChain, + const ASN1_TYPE* signTime); + DLL_EXPORT static bool VerifyCrl(CertChain& certsChain, STACK_OF(X509_CRL)* crls, + Pkcs7Context& pkcs7Context); + DLL_EXPORT static bool CompareX509Cert(const X509* certA, const std::string& base64Cert); + DLL_EXPORT static void WriteX509CrlToStream(std::ofstream& crlFile, X509_CRL* crl); + DLL_EXPORT static bool GetPublickeyBase64FromPemCert(const std::string& certStr, std::string& publicKey); + DLL_EXPORT static bool GetFingerprintBase64FromPemCert(const std::string& certStr, + std::string& fingerprint); + DLL_EXPORT static bool X509NameCompare(const X509_NAME* a, const X509_NAME* b); + DLL_EXPORT static bool GetPublickeyBase64(const X509* cert, std::string& publicKey); + DLL_EXPORT static int32_t CalculateLenAfterBase64Encode(int32_t len); + DLL_EXPORT static bool GetOrganizationFromPemCert(const std::string& certStr, std::string& organization); + 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 bool CheckAsn1TimeIsValid(const ASN1_TIME* asn1Time); + DLL_EXPORT static bool CheckAsn1TypeIsValid(const ASN1_TYPE* asn1Type); + +private: + static const uint32_t MIN_CERT_CHAIN_LEN_NEED_VERIFY_CRL; + static const int32_t OPENSSL_READ_CRL_MAX_TIME; + 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; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // HAP_CERT_VERIFY_OPENSSL_UTILS_H diff --git a/hapsigntool_cpp/utils/include/verify_hap_openssl_utils.h b/hapsigntool_cpp/utils/include/verify_hap_openssl_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..2960dfb8990f567c2745a9052983848f14223d0e --- /dev/null +++ b/hapsigntool_cpp/utils/include/verify_hap_openssl_utils.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024-2024 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 "export_define.h" +#include "byte_buffer.h" +#include "hap_verify_result.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" +#include "pkcs7_context.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 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 VerifyPkcs7(Pkcs7Context& pkcs7Context); + DLL_EXPORT static bool GetPublickeys(const CertChain& signCertChain, + std::vector& SignatureVec); + DLL_EXPORT static bool GetSignatures(const CertChain& signCertChain, + std::vector& SignatureVec); + 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 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); + DLL_EXPORT static bool GetPublickeyFromCertificate(const X509* ptrX509, + std::vector& publicKeyVec); + DLL_EXPORT static bool GetDerCert(X509* ptrX509, std::vector& SignatureVec); + 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 bool CheckDigestParameter(const DigestParameter& digestParameter); + + 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/hapsigntool_cpp/utils/signature_tools_utils.gni b/hapsigntool_cpp/utils/signature_tools_utils.gni new file mode 100644 index 0000000000000000000000000000000000000000..bc954c26a2f37368d7b0da0cb7ce19f76e0d8c4b --- /dev/null +++ b/hapsigntool_cpp/utils/signature_tools_utils.gni @@ -0,0 +1,27 @@ +# Copyright (c) 2024 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/cert_dn_utils.cpp", + "${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/hap_signer_block_utils.cpp", + "${signature_tools_utils}/src/string_utils.cpp", + "${signature_tools_utils}/src/verify_hap_openssl_utils.cpp", + "${signature_tools_utils}/src/byte_array_utils.cpp", + "${signature_tools_utils}/src/hash_utils.cpp", +] diff --git a/hapsigntool_cpp/utils/src/byte_array_utils.cpp b/hapsigntool_cpp/utils/src/byte_array_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9c7877a4f184fcca1b37eb5054ed155055048c4d --- /dev/null +++ b/hapsigntool_cpp/utils/src/byte_array_utils.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024-2024 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_array_utils.h" +#include "signature_tools_errno.h" +#include "securec.h" + +namespace OHOS { +namespace SignatureTools { +int ByteArrayUtils::InsertIntToByteArray(std::vector& desByte, int index, int num) +{ + if (index + sizeof(int) > desByte.size()) { + return RET_FAILED; + } + int pos = index; + desByte[pos] = (num >> TRIPLE_BIT_SIZE) & 0xff; + pos++; + desByte[pos] = (num >> DOUBLE_BIT_SIZE) & 0xff; + pos++; + desByte[pos] = (num >> BIT_SIZE) & 0xff; + pos++; + desByte[pos] = num & 0xff; + pos++; + return pos; +} + +int ByteArrayUtils::InsertShortToByteArray(std::vector& desByte, size_t desByteLen, int index, short num) +{ + if (index + HALF_INTEGER_BYTES > desByteLen) { + return RET_FAILED; + } + int pos = index; + desByte[pos] = (num >> BIT_SIZE) & 0xff; + pos++; + desByte[pos] = num & 0xff; + pos++; + return pos; +} + +int ByteArrayUtils::InsertByteToByteArray(std::vector& des, int start, std::vector src, int srcLen) +{ + if (src.size() < srcLen) { + return -1; + } + if (memcpy_s(des.data() + start, srcLen, src.data(), srcLen) != EOK) { + return -1; + } + return start + srcLen; +} + +int ByteArrayUtils::InsertCharToByteArray(std::vector& des, int start, std::string src) +{ + if (src.length() + start > des.size()) { + return RET_FAILED; + } + for (int i = 0; i < src.length(); ++i) { + des[i + start] = src[i]; + } + return start + src.length(); +} + +} // namespace SignatureTools +} // namespace OHOS diff --git a/hapsigntool_cpp/utils/src/cert_dn_utils.cpp b/hapsigntool_cpp/utils/src/cert_dn_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..afeda3c39286a0e585f9f520bff542e915b6eeb3 --- /dev/null +++ b/hapsigntool_cpp/utils/src/cert_dn_utils.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2024-2024 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 "cert_dn_utils.h" +#include "signature_tools_errno.h" +#include "constant.h" + +namespace OHOS { +namespace SignatureTools { + +int g_checkDn(std::string nameString, std::vector>& pairs) +{ + if (nameString.size() == 0) { + return FORMAT_ERROR; + } + std::vector tokens = StringUtils::SplitString(nameString.c_str(), ','); + for (std::string &pair : tokens) { + if (StringUtils::Trim(pair).size() == 0) { + return FORMAT_ERROR; + } + std::vector kvPair = StringUtils::SplitString(pair, '='); + if (kvPair.size() != DEFAULT_CERT_VERSION) { + return FORMAT_ERROR; + } + kvPair[0] = StringUtils::Trim(kvPair[0]); + kvPair[1] = StringUtils::Trim(kvPair[1]); + if (kvPair[1].size() == 0) { + return FORMAT_ERROR; + } + pairs.push_back({kvPair[0], kvPair[1]}); + } + return 0; +} + +X509_NAME* BuildDN(std::string nameString, X509_REQ* req) +{ + std::vector> pairs; + std::ostringstream oss; + oss << "Format error, must be \"X=xx,XX=xxx,...\". " + "Subject does not support either of key-value that contains commas or equal signs. " + "Please check: \"" << nameString << "\""; + int ret = g_checkDn(nameString, pairs); + if (ret == FORMAT_ERROR) { + PrintErrorNumberMsg("FORMAT_ERROR", FORMAT_ERROR, + oss.str().c_str()); + return nullptr; + } + X509_NAME* subject = nullptr; + subject = X509_REQ_get_subject_name(req); + if (!subject) { + SIGNATURE_TOOLS_LOGE("X509_NAME get failed !"); + return nullptr; + } + for (auto idx = pairs.cbegin(); idx != pairs.cend(); idx++) { + if (OBJ_txt2nid(idx->first.c_str()) == NID_undef) { + PrintErrorNumberMsg("COMMAND_PARAM_ERROR", COMMAND_PARAM_ERROR, + "Error params near:" + nameString + " Reason: Unknown object id - " + idx->first + + " - passed to distinguished name"); + return nullptr; + } + X509_NAME_add_entry_by_txt(subject, idx->first.c_str(), MBSTRING_ASC, + (const unsigned char*)idx->second.c_str(), -1, -1, 0); + } + return subject; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/utils/src/file_utils.cpp b/hapsigntool_cpp/utils/src/file_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..53002f7a4be141fb0f9431cd6d0575ae051584d5 --- /dev/null +++ b/hapsigntool_cpp/utils/src/file_utils.cpp @@ -0,0 +1,442 @@ +/* + * Copyright (c) 2024-2024 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 "string_utils.h" +#include "signature_tools_errno.h" +#include "file_utils.h" + +namespace OHOS { +namespace SignatureTools { +namespace fs = std::filesystem; + +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/"; +bool FileUtils::IsEmpty(std::string cs) +{ + if (cs.length() == 0) { + return true; + } + return false; +} + +bool FileUtils::IsSpaceEnough(const std::string& filePath, const int64_t requiredSpace) +{ + uint64_t freeSpace = 0; + struct statfs diskStatfs; + int ret = statfs(filePath.c_str(), &diskStatfs); + if (ret >= 0) { + freeSpace = (uint64_t)diskStatfs.f_bsize * (uint64_t)diskStatfs.f_bavail; + } else { + SIGNATURE_TOOLS_LOGE("statfs fail, error code = %d", ret); + } + return freeSpace >= static_cast(requiredSpace); +} + +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()); + 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; +} + +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(); + std::string buffer(FILE_BUFFER_BLOCK, 0); + size_t hasReadLen = 0; + while (hasReadLen < length && input) { + int readLen = static_cast(std::min(length - hasReadLen, (size_t)FILE_BUFFER_BLOCK)); + input.read(&buffer[0], readLen); + bool flag = (input.gcount() != readLen); + if (flag) { + SIGNATURE_TOOLS_LOGE("read %zu bytes data less than %zu", hasReadLen, length); + return -1; + } + ret.append(&buffer[0], readLen); + hasReadLen += input.gcount(); + } + if (hasReadLen != length) { + SIGNATURE_TOOLS_LOGE("read %zu bytes data less than %zu", hasReadLen, length); + return -1; + } + return RET_OK; +} + +bool FileUtils::AppendWriteFileByOffsetToFile(std::ifstream& input, std::ofstream& out, size_t offset, size_t size) +{ + if (input.rdstate() != 0) { + SIGNATURE_TOOLS_LOGE("input failed."); + return false; + } + if (out.rdstate() != 0) { + SIGNATURE_TOOLS_LOGE("Failed get out stream"); + return false; + } + input.seekg(offset); + if (WriteInputToOutPut(input, out, size) < 0) { + SIGNATURE_TOOLS_LOGE("Error: writeInputToOutPut"); + return false; + } + return true; +} + +bool FileUtils::AppendWriteFileToFile(const std::string& inputFile, const std::string& outputFile) +{ + std::ifstream input(inputFile, std::ios::binary); + std::ofstream output(outputFile, std::ios::binary | std::ios::app); + bool flag = (0 != input.rdstate()); + if (flag) { + SIGNATURE_TOOLS_LOGE("Failed to get input stream object!"); + return false; + } + flag = (0 != output.rdstate()); + if (flag) { + SIGNATURE_TOOLS_LOGE("Failed to get output stream object!"); + return false; + } + char* buffer = new char[FILE_BUFFER_BLOCK]; + while (!input.eof()) { + input.read(buffer, FILE_BUFFER_BLOCK); + + if (input.fail() && !input.eof()) { + SIGNATURE_TOOLS_LOGE("error occurred while reading data"); + delete[]buffer; + return false; + } + std::streamsize readLen = input.gcount(); + if (readLen > 0) { + output.write(buffer, readLen); + } + if (!output) { + SIGNATURE_TOOLS_LOGE("error occurred while writing data"); + delete[]buffer; + return false; + } + } + delete[]buffer; + return true; +} + +bool FileUtils::AppendWriteByteToFile(const std::string& bytes, const std::string& outputFile) +{ + std::ofstream output(outputFile, std::ios::binary | std::ios::app); + bool flag = (WriteByteToOutFile(bytes, output) == false); + if (flag) { + SIGNATURE_TOOLS_LOGE("Failed to write data to output stream, outfile: %s", outputFile.c_str()); + return false; + } + return true; +} + +int FileUtils::WriteInputToOutPut(std::ifstream& input, std::ofstream& output, size_t length) +{ + static Uscript::ThreadPool readPool(1); + static Uscript::ThreadPool writePool(1); + std::future readTask; + std::vector> writeTasks; + int result = RET_OK; + auto writeFunc = [&result] (std::ofstream& outStream, char* data, int dataSize) { + outStream.write(data, dataSize); + if (!outStream.good()) { + result = IO_ERROR; + delete[] data; + return; + } + delete[] data; + }; + auto readFunc = [&output, &writeFunc, &writeTasks, &result] (std::ifstream& in, int dataSize) { + while (in) { + char* buf = new (std::nothrow)char[FILE_BUFFER_BLOCK]; + if (buf == NULL) { + result = RET_FAILED; + return; + } + int min = std::min(dataSize, FILE_BUFFER_BLOCK); + in.read(buf, min); + dataSize -= in.gcount(); + writeTasks.push_back(writePool.Enqueue(writeFunc, std::ref(output), buf, min)); + if (dataSize <= 0) { + break; + } + } + // After the file is written, datasize must be 0, so the if condition will never hold + if (dataSize != 0) { + SIGNATURE_TOOLS_LOGE("write error!"); + result = IO_ERROR; + return; + } + }; + readTask = readPool.Enqueue(readFunc, std::ref(input), length); + readTask.wait(); + for (std::future& task : writeTasks) { + task.wait(); + } + 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::WriteByteToOutFile(const std::string& bytes, const std::string& outFile) +{ + std::ofstream ops(outFile, std::ios::binary); + bool flag = (WriteByteToOutFile(bytes, ops) == false); + if (flag) { + SIGNATURE_TOOLS_LOGE("Failed to write data to ops, outfile: %s", outFile.c_str()); + return false; + } + return true; +} + +bool FileUtils::WriteByteToOutFile(const std::string& bytes, std::ofstream& outFile) +{ + if (outFile.rdstate() != 0) { + SIGNATURE_TOOLS_LOGE("Failed to get output stream object, outfile"); + return false; + } + outFile.write(&bytes[0], bytes.size()); + if (outFile.rdstate() != 0) { + SIGNATURE_TOOLS_LOGE("Failed to write data to ops, outfile "); + return false; + } + outFile.flush(); + if (outFile.rdstate() != 0) { + SIGNATURE_TOOLS_LOGE("Flush error"); + return false; + } + return true; +} + +bool FileUtils::WriteByteToOutFile(const std::vector& bytes, std::ofstream& outFile) +{ + if (outFile.rdstate() != 0) { + SIGNATURE_TOOLS_LOGE("Failed to get output stream object, outfile"); + return false; + } + outFile.write((char*)&bytes[0], bytes.size()); + if (outFile.rdstate() != 0) { + SIGNATURE_TOOLS_LOGE("Failed to write data to ops, outfile "); + return false; + } + outFile.flush(); + if (outFile.rdstate() != 0) { + SIGNATURE_TOOLS_LOGE("Flush error"); + return false; + } + 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; +} + +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/utils/src/hap_signer_block_utils.cpp b/hapsigntool_cpp/utils/src/hap_signer_block_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c449d49f561a4d269fd30af5bbea64c02b8de082 --- /dev/null +++ b/hapsigntool_cpp/utils/src/hap_signer_block_utils.cpp @@ -0,0 +1,686 @@ +/* + * Copyright (c) 2024-2024 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 "hap_signer_block_utils.h" +#include +#include +#include + +#include "algorithm" +#include "openssl/evp.h" +#include "securec.h" +#include "byte_buffer_data_source.h" +#include "file_data_source.h" +#include "verify_hap_openssl_utils.h" +#include "signature_tools_log.h" +#include "signature_tools_errno.h" + +namespace OHOS { +namespace SignatureTools { +const int64_t HapSignerBlockUtils::HAP_SIG_BLOCK_MAGIC_LOW_OLD = 2334950737560224072LL; +const int64_t HapSignerBlockUtils::HAP_SIG_BLOCK_MAGIC_HIGH_OLD = 3617552046287187010LL; +const int64_t HapSignerBlockUtils::HAP_SIG_BLOCK_MAGIC_LOW = 7451613641622775868LL; +const int64_t HapSignerBlockUtils::HAP_SIG_BLOCK_MAGIC_HIGH = 4497797983070462062LL; + +/* 1MB = 1024 * 1024 Bytes */ +const int64_t HapSignerBlockUtils::CHUNK_SIZE = 1048576LL; + +const int32_t HapSignerBlockUtils::HAP_SIG_BLOCK_MIN_SIZE = 32; +const int32_t HapSignerBlockUtils::ZIP_HEAD_OF_SIGNING_BLOCK_LENGTH = 32; + +const int32_t HapSignerBlockUtils::ZIP_EOCD_SEG_MIN_SIZE = 22; +const int32_t HapSignerBlockUtils::ZIP_EOCD_SEGMENT_FLAG = 0x06054b50; +const int32_t HapSignerBlockUtils::ZIP_EOCD_COMMENT_LENGTH_OFFSET = 20; +const int32_t HapSignerBlockUtils::ZIP_CD_OFFSET_IN_EOCD = 16; +const int32_t HapSignerBlockUtils::ZIP_CD_SIZE_OFFSET_IN_EOCD = 12; +const int32_t HapSignerBlockUtils::ZIP_BLOCKS_NUM_NEED_DIGEST = 3; + +const char HapSignerBlockUtils::ZIP_FIRST_LEVEL_CHUNK_PREFIX = 0x5a; +const char HapSignerBlockUtils::ZIP_SECOND_LEVEL_CHUNK_PREFIX = 0xa5; + +/* + * The package of hap is ZIP format, and contains four segments: contents of Zip entry, + * hap signatures block, central directory and end of central directory. + * The function will find the data segment of hap signature block from hap file. + */ +bool HapSignerBlockUtils::FindHapSignature(RandomAccessFile& hapFile, SignatureInfo& signInfo) +{ + std::pair eocdAndOffsetInFile; + if (!FindEocdInHap(hapFile, eocdAndOffsetInFile)) { + SIGNATURE_TOOLS_LOGE("find EoCD failed"); + return false; + } + + signInfo.hapEocd = eocdAndOffsetInFile.first; + signInfo.hapEocdOffset = eocdAndOffsetInFile.second; + if (!GetCentralDirectoryOffset(signInfo.hapEocd, signInfo.hapEocdOffset, signInfo.hapCentralDirOffset)) { + SIGNATURE_TOOLS_LOGE("get CD offset failed"); + PrintErrorNumberMsg("verify", VERIFY_ERROR, "ZIP End of Central Directory not found"); + return false; + } + + if (!FindHapSigningBlock(hapFile, signInfo.hapCentralDirOffset, signInfo)) { + SIGNATURE_TOOLS_LOGE("find signing block failed"); + return false; + } + return true; +} + +bool HapSignerBlockUtils::FindEocdInHap(RandomAccessFile& hapFile, std::pair& eocd) +{ + /* + * EoCD has an optional comment block. Most hap packages do not contain this block. + * For hap packages without comment block, EoCD is the last 22 bytes of hap file. + * Try as a hap without comment block first to avoid unnecessarily reading more data. + */ + if (FindEocdInHap(hapFile, 0, eocd)) { + SIGNATURE_TOOLS_LOGD("Find EoCD of Zip file"); + return true; + } + /* + * If EoCD contain the comment block, we should find it from the offset of (fileLen - maxCommentSize - 22). + * The max size of comment block is 65535, because the comment length is an unsigned 16-bit number. + */ + return FindEocdInHap(hapFile, USHRT_MAX, eocd); +} + +bool HapSignerBlockUtils::FindEocdInHap(RandomAccessFile& hapFile, unsigned short maxCommentSize, + std::pair& eocd) +{ + int64_t fileLength = hapFile.GetLength(); + /* check whether has enough space for EoCD in the file. */ + if (fileLength < ZIP_EOCD_SEG_MIN_SIZE) { + SIGNATURE_TOOLS_LOGE("file length %" PRId64 " is too smaller", fileLength); + return false; + } + + int32_t searchRange = static_cast(maxCommentSize) + ZIP_EOCD_SEG_MIN_SIZE; + if (fileLength < static_cast(searchRange)) { + searchRange = static_cast(fileLength); + } + + ByteBuffer searchEocdBuffer(searchRange); + int64_t searchRangeOffset = fileLength - searchEocdBuffer.GetCapacity(); + int64_t ret = hapFile.ReadFileFullyFromOffset(searchEocdBuffer, searchRangeOffset); + if (ret < 0) { + SIGNATURE_TOOLS_LOGE("read data from hap file error: %" PRId64, ret); + return false; + } + + int32_t eocdOffsetInSearchBuffer = 0; + if (!FindEocdInSearchBuffer(searchEocdBuffer, eocdOffsetInSearchBuffer)) { + SIGNATURE_TOOLS_LOGE("eocd is not found"); + return false; + } + + searchEocdBuffer.SetPosition(eocdOffsetInSearchBuffer); + searchEocdBuffer.Slice(); + eocd.first = searchEocdBuffer; + eocd.second = searchRangeOffset + eocdOffsetInSearchBuffer; + return true; +} + + +/* +* 4-bytes: End of central directory flag +* 2-bytes: Number of this disk +* 2-bytes: Number of the disk with the start of central directory +* 2-bytes: Total number of entries in the central directory on this disk +* 2-bytes: Total number of entries in the central directory +* 4-bytes: Size of central directory +* 4-bytes: offset of central directory in zip file +* 2-bytes: ZIP file comment length, the value n is in the range of [0, 65535] +* n-bytes: ZIP Comment block data +* +* This function find Eocd by searching Eocd flag from input buffer(searchBuffer) and +* making sure the comment length is equal to the expected value. +*/ +bool HapSignerBlockUtils::FindEocdInSearchBuffer(ByteBuffer& searchBuffer, int& offset) +{ + int32_t searchBufferSize = searchBuffer.GetCapacity(); + if (searchBufferSize < ZIP_EOCD_SEG_MIN_SIZE) { + SIGNATURE_TOOLS_LOGE("The size of searchBuffer %d is smaller than min size of Eocd", + searchBufferSize); + return false; + } + + int32_t currentOffset = searchBufferSize - ZIP_EOCD_SEG_MIN_SIZE; + while (currentOffset >= 0) { + int32_t hapEocdSegmentFlag; + if (searchBuffer.GetInt32(currentOffset, hapEocdSegmentFlag) && + (hapEocdSegmentFlag == ZIP_EOCD_SEGMENT_FLAG)) { + unsigned short commentLength; + int32_t expectedCommentLength = searchBufferSize - ZIP_EOCD_SEG_MIN_SIZE - currentOffset; + if (searchBuffer.GetUInt16(currentOffset + ZIP_EOCD_COMMENT_LENGTH_OFFSET, commentLength) && + static_cast(commentLength) == expectedCommentLength) { + offset = currentOffset; + return true; + } + } + currentOffset--; + } + return false; +} + +bool HapSignerBlockUtils::GetCentralDirectoryOffset(ByteBuffer& eocd, int64_t eocdOffset, + int64_t& centralDirectoryOffset) +{ + uint32_t offsetValue; + uint32_t sizeValue; + if (!eocd.GetUInt32(ZIP_CD_OFFSET_IN_EOCD, offsetValue) || + !eocd.GetUInt32(ZIP_CD_SIZE_OFFSET_IN_EOCD, sizeValue)) { + SIGNATURE_TOOLS_LOGE("GetUInt32 failed"); + return false; + } + + centralDirectoryOffset = static_cast(offsetValue); + if (centralDirectoryOffset > eocdOffset) { + SIGNATURE_TOOLS_LOGE("centralDirOffset %" PRId64 " is larger than eocdOffset %" PRId64, + centralDirectoryOffset, eocdOffset); + return false; + } + + int64_t centralDirectorySize = static_cast(sizeValue); + if (centralDirectoryOffset + centralDirectorySize != eocdOffset) { + SIGNATURE_TOOLS_LOGE("centralDirOffset %" PRId64 " add centralDirSize %" PRId64 " is" + " not equal to eocdOffset %" PRId64, centralDirectoryOffset, + centralDirectorySize, eocdOffset); + return false; + } + return true; +} + +bool HapSignerBlockUtils::GetCentralDirectorySize(ByteBuffer& eocd, long& centralDirectorySize) +{ + uint32_t cdSize; + if (!eocd.GetUInt32(ZIP_CD_SIZE_OFFSET_IN_EOCD, cdSize)) { + SIGNATURE_TOOLS_LOGE("GetUInt32 failed"); + return false; + } + centralDirectorySize = (long)cdSize; + return true; +} + +bool HapSignerBlockUtils::SetUnsignedInt32(ByteBuffer& buffer, int32_t offset, int64_t value) +{ + if ((value < 0) || (value > static_cast(UINT_MAX))) { + SIGNATURE_TOOLS_LOGE("uint32 value of out range: %" PRId64, value); + return false; + } + buffer.PutInt32(offset, static_cast(value)); + return true; +} + +bool HapSignerBlockUtils::FindHapSigningBlock(RandomAccessFile& hapFile, int64_t centralDirOffset, + SignatureInfo& signInfo) +{ + if (centralDirOffset < HAP_SIG_BLOCK_MIN_SIZE) { + SIGNATURE_TOOLS_LOGE("HAP too small for HAP Signing Block: %" PRId64, centralDirOffset); + return false; + } + /* + * read hap signing block head, it's format: + * int32: blockCount + * int64: size + * 16 bytes: magic + * int32: version + */ + ByteBuffer hapBlockHead(ZIP_HEAD_OF_SIGNING_BLOCK_LENGTH); + int64_t ret = hapFile.ReadFileFullyFromOffset(hapBlockHead, + centralDirOffset - hapBlockHead.GetCapacity()); + if (ret < 0) { + SIGNATURE_TOOLS_LOGE("read hapBlockHead error: %" PRId64, ret); + return false; + } + HapSignBlockHead hapSignBlockHead; + if (!ParseSignBlockHead(hapSignBlockHead, hapBlockHead)) { + SIGNATURE_TOOLS_LOGE("ParseSignBlockHead failed"); + return false; + } + + if (!CheckSignBlockHead(hapSignBlockHead)) { + SIGNATURE_TOOLS_LOGE("hapSignBlockHead is invalid"); + return false; + } + + signInfo.version = hapSignBlockHead.version; + int64_t blockArrayLen = hapSignBlockHead.hapSignBlockSize - ZIP_HEAD_OF_SIGNING_BLOCK_LENGTH; + int64_t hapSignBlockOffset = centralDirOffset - hapSignBlockHead.hapSignBlockSize; + if (hapSignBlockOffset < 0) { + SIGNATURE_TOOLS_LOGE("HAP Signing Block offset out of range %" PRId64, hapSignBlockOffset); + return false; + } + signInfo.hapSigningBlockOffset = hapSignBlockOffset; + return FindHapSubSigningBlock(hapFile, hapSignBlockHead.blockCount, + blockArrayLen, hapSignBlockOffset, signInfo); +} + +bool HapSignerBlockUtils::CheckSignBlockHead(const HapSignBlockHead& hapSignBlockHead) +{ + int64_t magicLow = HAP_SIG_BLOCK_MAGIC_LOW; + int64_t magicHigh = HAP_SIG_BLOCK_MAGIC_HIGH; + if (hapSignBlockHead.version < VERSION_FOR_NEW_MAGIC_NUM) { + magicLow = HAP_SIG_BLOCK_MAGIC_LOW_OLD; + magicHigh = HAP_SIG_BLOCK_MAGIC_HIGH_OLD; + } + + if ((hapSignBlockHead.hapSignBlockMagicLo != magicLow) || + (hapSignBlockHead.hapSignBlockMagicHi != magicHigh)) { + SIGNATURE_TOOLS_LOGE("No HAP Signing Block before ZIP Central Directory"); + return false; + } + + if ((hapSignBlockHead.hapSignBlockSize < ZIP_HEAD_OF_SIGNING_BLOCK_LENGTH) || + (hapSignBlockHead.hapSignBlockSize > MAX_HAP_SIGN_BLOCK_SIZE)) { + SIGNATURE_TOOLS_LOGE("HAP Signing Block size out of range %" PRId64, + hapSignBlockHead.hapSignBlockSize); + return false; + } + + if (hapSignBlockHead.blockCount > MAX_BLOCK_COUNT) { + SIGNATURE_TOOLS_LOGE("HAP Signing Block count out of range %d", hapSignBlockHead.blockCount); + return false; + } + + return true; +} + +bool HapSignerBlockUtils::ParseSignBlockHead(HapSignBlockHead& hapSignBlockHead, ByteBuffer& hapBlockHead) +{ + return hapBlockHead.GetInt32(hapSignBlockHead.blockCount) && + hapBlockHead.GetInt64(hapSignBlockHead.hapSignBlockSize) && + hapBlockHead.GetInt64(hapSignBlockHead.hapSignBlockMagicLo) && + hapBlockHead.GetInt64(hapSignBlockHead.hapSignBlockMagicHi) && + hapBlockHead.GetInt32(hapSignBlockHead.version); +} + +bool HapSignerBlockUtils::ParseSubSignBlockHead(HapSubSignBlockHead& subSignBlockHead, + ByteBuffer& hapBlockHead) +{ + return hapBlockHead.GetUInt32(subSignBlockHead.type) && + hapBlockHead.GetUInt32(subSignBlockHead.length) && + hapBlockHead.GetUInt32(subSignBlockHead.offset); +} + +/* + * Hap Sign Block Format: + * HapSubSignBlock1_Head + * HapSubSignBlock2_Head + * ... + * HapSubSignBlockn_Head + * HapSubSignBlock1_data + * HapSubSignBlock2_data + * ... + * HapSubSignBlockn_data + * hap signing block head + * + * This function reads the head of the HapSubSignBlocks, + * and then reads the corresponding data of each block according to the offset provided by the head + */ +bool HapSignerBlockUtils::FindHapSubSigningBlock(RandomAccessFile& hapFile, + int32_t blockCount, + int64_t blockArrayLen, + int64_t hapSignBlockOffset, + SignatureInfo& signInfo) +{ + int64_t offsetMax = hapSignBlockOffset + blockArrayLen; + int64_t readLen = 0; + int64_t readHeadOffset = hapSignBlockOffset; + for (int32_t i = 0; i < blockCount; i++) { + ByteBuffer hapBlockHead(ZIP_CD_SIZE_OFFSET_IN_EOCD); + int64_t ret = hapFile.ReadFileFullyFromOffset(hapBlockHead, readHeadOffset); + if (ret < 0) { + return false; + } + HapSubSignBlockHead subSignBlockHead; + if (!ParseSubSignBlockHead(subSignBlockHead, hapBlockHead)) { + SIGNATURE_TOOLS_LOGE("ParseSubSignBlockHead failed"); + return false; + } + readLen += sizeof(HapSubSignBlockHead); + + readHeadOffset += sizeof(HapSubSignBlockHead); + if (readHeadOffset > offsetMax) { + SIGNATURE_TOOLS_LOGE("find %dst next head offset error", i); + return false; + } + + int64_t headOffset = static_cast(subSignBlockHead.offset); + int64_t headLength = static_cast(subSignBlockHead.length); + /* check subSignBlockHead */ + if ((offsetMax - headOffset) < hapSignBlockOffset) { + SIGNATURE_TOOLS_LOGE("Find %dst subblock data offset error", i); + return false; + } + if ((blockArrayLen - headLength) < readLen) { + SIGNATURE_TOOLS_LOGE("no enough data to be read for %dst subblock", i); + return false; + } + + int64_t dataOffset = hapSignBlockOffset + headOffset; + ByteBuffer signBuffer(subSignBlockHead.length); + if ((ret = hapFile.ReadFileFullyFromOffset(signBuffer, dataOffset)) < 0) { + SIGNATURE_TOOLS_LOGE("read %dst subblock error: %" PRId64, i, ret); + return false; + } + readLen += headLength; + + if (!ClassifyHapSubSigningBlock(signInfo, signBuffer, subSignBlockHead.type)) { + SIGNATURE_TOOLS_LOGE("subSigningBlock error, type is %d", subSignBlockHead.type); + return false; + } + } + + /* size of block must be equal to the sum of all subblocks length */ + if (readLen != blockArrayLen) { + SIGNATURE_TOOLS_LOGE("Len: %" PRId64 " is not equal blockArrayLen: %" PRId64, + readLen, blockArrayLen); + return false; + } + return true; +} + +bool HapSignerBlockUtils::ClassifyHapSubSigningBlock(SignatureInfo& signInfo, + const ByteBuffer& subBlock, uint32_t type) +{ + bool ret = false; + switch (type) { + case HAP_SIGN_BLOB: + { + if (signInfo.hapSignatureBlock.GetCapacity() != 0) { + SIGNATURE_TOOLS_LOGE("find more than one hap sign block"); + break; + } + signInfo.hapSignatureBlock = subBlock; + ret = true; + break; + } + case PROFILE_BLOB: + case PROOF_ROTATION_BLOB: + case PROPERTY_BLOB: + { + OptionalBlock optionalBlock; + optionalBlock.optionalType = static_cast(type); + optionalBlock.optionalBlockValue = subBlock; + signInfo.optionBlocks.push_back(optionalBlock); + ret = true; + break; + } + default: + break; + } + return ret; +} + +bool HapSignerBlockUtils::GetOptionalBlockIndex(std::vector& optionBlocks, + int32_t type, + int& index) +{ + int32_t len = static_cast(optionBlocks.size()); + for (int32_t i = 0; i < len; i++) { + if (optionBlocks[i].optionalType == type) { + index = i; + return true; + } + } + SIGNATURE_TOOLS_LOGE("get optional block type:%d failed.", type); + return false; +} + +bool HapSignerBlockUtils::VerifyHapIntegrity( + Pkcs7Context& digestInfo, RandomAccessFile& hapFile, SignatureInfo& signInfo) +{ + if (!SetUnsignedInt32(signInfo.hapEocd, ZIP_CD_OFFSET_IN_EOCD, signInfo.hapSigningBlockOffset)) { + SIGNATURE_TOOLS_LOGE("Set central dir offset failed"); + return false; + } + + int64_t centralDirSize = signInfo.hapEocdOffset - signInfo.hapCentralDirOffset; + FileDataSource contentsZip(hapFile, 0, signInfo.hapSigningBlockOffset, 0); + FileDataSource centralDir(hapFile, signInfo.hapCentralDirOffset, centralDirSize, 0); + ByteBufferDataSource eocd(signInfo.hapEocd); + DataSource* content[ZIP_BLOCKS_NUM_NEED_DIGEST] = {&contentsZip, ¢ralDir, &eocd}; + int32_t nId = VerifyHapOpensslUtils::GetDigestAlgorithmId(digestInfo.digestAlgorithm); + DigestParameter digestParam = GetDigestParameter(nId); + ByteBuffer chunkDigest; + if (!ComputeDigestsForEachChunk(digestParam, content, ZIP_BLOCKS_NUM_NEED_DIGEST, chunkDigest)) { + SIGNATURE_TOOLS_LOGE("Compute Content Digests failed, alg: %d", nId); + return false; + } + + ByteBuffer actualDigest; + if (!ComputeDigestsWithOptionalBlock(digestParam, signInfo.optionBlocks, chunkDigest, actualDigest)) { + SIGNATURE_TOOLS_LOGE("Compute Final Digests failed, alg: %d", nId); + return false; + } + + if (!digestInfo.content.IsEqual(actualDigest)) { + SIGNATURE_TOOLS_LOGE("digest of contents verify failed, alg %d", nId); + return false; + } + return true; +} + +bool HapSignerBlockUtils::ComputeDigestsWithOptionalBlock(const DigestParameter& digestParam, + const std::vector& optionalBlocks, + const ByteBuffer& chunkDigest, + ByteBuffer& finalDigest) +{ + unsigned char out[EVP_MAX_MD_SIZE]; + int32_t digestLen = VerifyHapOpensslUtils::GetDigest(chunkDigest, optionalBlocks, digestParam, out); + if (digestLen != digestParam.digestOutputSizeBytes) { + SIGNATURE_TOOLS_LOGE("GetDigest failed, outLen is not right, %u, %d", + digestLen, digestParam.digestOutputSizeBytes); + return false; + } + + finalDigest.SetCapacity(digestParam.digestOutputSizeBytes); + finalDigest.PutData(0, reinterpret_cast(out), digestParam.digestOutputSizeBytes); + return true; +} + +bool HapSignerBlockUtils::GetSumOfChunkDigestLen(DataSource* contents[], int32_t len, + int32_t chunkDigestLen, int& chunkCount, + int& sumOfChunkDigestLen) +{ + for (int32_t i = 0; i < len; i++) { + if (contents[i] == nullptr) { + SIGNATURE_TOOLS_LOGE("contents[%d] is nullptr", i); + return false; + } + contents[i]->Reset(); + chunkCount += GetChunkCount(contents[i]->Remaining(), CHUNK_SIZE); + } + + if (chunkCount <= 0) { + SIGNATURE_TOOLS_LOGE("no content for digest"); + return false; + } + if (chunkCount == 0) { + SIGNATURE_TOOLS_LOGE("no content for digest"); + return false; + } + if (chunkDigestLen < 0 || ((INT_MAX - ZIP_CHUNK_DIGEST_PRIFIX_LEN) / chunkCount) < chunkDigestLen) { + SIGNATURE_TOOLS_LOGE("overflow chunkCount: %d, chunkDigestLen: %d", + chunkCount, chunkDigestLen); + return false; + } + + sumOfChunkDigestLen = ZIP_CHUNK_DIGEST_PRIFIX_LEN + chunkCount * chunkDigestLen; + return true; +} + +bool HapSignerBlockUtils::ComputeDigestsForEachChunk(const DigestParameter& digestParam, + DataSource* contents[], int32_t len, ByteBuffer& result) +{ + int32_t chunkCount = 0; + int32_t sumOfChunksLen = 0; + if (!GetSumOfChunkDigestLen(contents, len, digestParam.digestOutputSizeBytes, chunkCount, sumOfChunksLen)) { + SIGNATURE_TOOLS_LOGE("GetSumOfChunkDigestLen failed"); + return false; + } + result.SetCapacity(sumOfChunksLen); + result.PutByte(0, ZIP_FIRST_LEVEL_CHUNK_PREFIX); + result.PutInt32(1, chunkCount); + + int32_t chunkIndex = 0; + unsigned char out[EVP_MAX_MD_SIZE]; + unsigned char chunkContentPrefix[ZIP_CHUNK_DIGEST_PRIFIX_LEN] = { + (unsigned char)ZIP_SECOND_LEVEL_CHUNK_PREFIX, 0, 0, 0, 0}; + + int32_t offset = ZIP_CHUNK_DIGEST_PRIFIX_LEN; + for (int32_t i = 0; i < len; i++) { + while (contents[i]->HasRemaining()) { + int32_t chunkSize = std::min(contents[i]->Remaining(), CHUNK_SIZE); + if (!InitDigestPrefix(digestParam, chunkContentPrefix, chunkSize)) { + SIGNATURE_TOOLS_LOGE("InitDigestPrefix failed"); + return false; + } + + if (!contents[i]->ReadDataAndDigestUpdate(digestParam, chunkSize)) { + SIGNATURE_TOOLS_LOGE("Copy Partial Buffer failed, count: %d", chunkIndex); + return false; + } + + int32_t digestLen = VerifyHapOpensslUtils::GetDigest(digestParam, out); + if (digestLen != digestParam.digestOutputSizeBytes) { + SIGNATURE_TOOLS_LOGE("GetDigest failed len: %d digestSizeBytes: %d", + digestLen, digestParam.digestOutputSizeBytes); + return false; + } + result.PutData(offset, reinterpret_cast(out), digestParam.digestOutputSizeBytes); + offset += digestLen; + chunkIndex++; + } + } + return true; +} + +DigestParameter HapSignerBlockUtils::GetDigestParameter(int32_t nId) +{ + DigestParameter digestParam; + digestParam.digestOutputSizeBytes = VerifyHapOpensslUtils::GetDigestAlgorithmOutputSizeBytes(nId); + digestParam.md = EVP_get_digestbynid(nId); + digestParam.ptrCtx = EVP_MD_CTX_create(); + EVP_MD_CTX_init(digestParam.ptrCtx); + return digestParam; +} + +int32_t HapSignerBlockUtils::GetChunkCount(int64_t inputSize, int64_t chunkSize) +{ + if (chunkSize <= 0 || inputSize > LLONG_MAX - chunkSize) { + return 0; + } + if (chunkSize == 0) + return 0; + int64_t res = (inputSize + chunkSize - 1) / chunkSize; + if (res > INT_MAX || res < 0) { + return 0; + } + return static_cast(res); +} + +bool HapSignerBlockUtils::InitDigestPrefix(const DigestParameter& digestParam, + unsigned char(&chunkContentPrefix)[ZIP_CHUNK_DIGEST_PRIFIX_LEN], + int32_t chunkLen) +{ + if (memcpy_s((chunkContentPrefix + 1), ZIP_CHUNK_DIGEST_PRIFIX_LEN - 1, + (&chunkLen), sizeof(chunkLen)) != EOK) { + SIGNATURE_TOOLS_LOGE("memcpy_s failed"); + return false; + } + + if (!VerifyHapOpensslUtils::DigestInit(digestParam)) { + SIGNATURE_TOOLS_LOGE("DigestInit failed"); + return false; + } + + if (!VerifyHapOpensslUtils::DigestUpdate(digestParam, chunkContentPrefix, ZIP_CHUNK_DIGEST_PRIFIX_LEN)) { + SIGNATURE_TOOLS_LOGE("DigestUpdate failed"); + return false; + } + return true; +} + +int64_t HapSignerBlockUtils::CreatTestZipFile(const std::string& pathFile, SignatureInfo& signInfo) +{ + std::ofstream hapFile(pathFile.c_str(), std::ios::binary | std::ios::out | std::ios::trunc); + if (!hapFile.is_open()) { + return 0; + } + char block[TEST_FILE_BLOCK_LENGTH] = {0}; + /* input contents of ZIP entries */ + hapFile.seekp(0, std::ios_base::beg); + hapFile.write(block, sizeof(block)); + /* input sign block */ + HapSubSignBlockHead signBlob; + HapSubSignBlockHead profileBlob; + HapSubSignBlockHead propertyBlob; + CreateHapSubSignBlockHead(signBlob, profileBlob, propertyBlob); + hapFile.write(reinterpret_cast(&signBlob), sizeof(signBlob)); + hapFile.write(reinterpret_cast(&profileBlob), sizeof(profileBlob)); + hapFile.write(reinterpret_cast(&propertyBlob), sizeof(propertyBlob)); + for (int32_t i = 0; i < TEST_FILE_BLOCK_COUNT; i++) { + hapFile.write(block, sizeof(block)); + } + int32_t blockCount = TEST_FILE_BLOCK_COUNT; + hapFile.write(reinterpret_cast(&blockCount), sizeof(blockCount)); + int64_t signBlockSize = (sizeof(HapSubSignBlockHead) + sizeof(block)) * TEST_FILE_BLOCK_COUNT + + HapSignerBlockUtils::ZIP_HEAD_OF_SIGNING_BLOCK_LENGTH; + hapFile.write(reinterpret_cast(&signBlockSize), sizeof(signBlockSize)); + int64_t magic = HapSignerBlockUtils::HAP_SIG_BLOCK_MAGIC_LOW_OLD; + hapFile.write(reinterpret_cast(&magic), sizeof(magic)); + magic = HapSignerBlockUtils::HAP_SIG_BLOCK_MAGIC_HIGH_OLD; + hapFile.write(reinterpret_cast(&magic), sizeof(magic)); + int32_t version = 1; + hapFile.write(reinterpret_cast(&version), sizeof(version)); + /* input central direction */ + hapFile.write(block, sizeof(block)); + /* input end of central direction */ + int32_t zidEocdSign = HapSignerBlockUtils::ZIP_EOCD_SEGMENT_FLAG; + hapFile.write(reinterpret_cast(&zidEocdSign), sizeof(zidEocdSign)); + hapFile.write(reinterpret_cast(&magic), sizeof(magic)); + uint32_t centralDirLen = sizeof(block); + hapFile.write(reinterpret_cast(¢ralDirLen), sizeof(centralDirLen)); + uint32_t centralDirOffset = TEST_FILE_BLOCK_LENGTH + signBlockSize; + hapFile.write(reinterpret_cast(¢ralDirOffset), sizeof(centralDirOffset)); + short eocdCommentLen = 0; + hapFile.write(reinterpret_cast(&eocdCommentLen), sizeof(eocdCommentLen)); + hapFile.close(); + signInfo.hapCentralDirOffset = centralDirOffset; + signInfo.hapEocdOffset = centralDirOffset + centralDirLen; + signInfo.hapSignatureBlock.SetCapacity(TEST_FILE_BLOCK_LENGTH); + signInfo.hapSignatureBlock.PutData(0, block, sizeof(block)); + int64_t sumLen = signInfo.hapEocdOffset + sizeof(zidEocdSign) + sizeof(centralDirLen) + + sizeof(centralDirOffset) + sizeof(magic) + sizeof(eocdCommentLen); + return sumLen; +} + +void HapSignerBlockUtils::CreateHapSubSignBlockHead(HapSubSignBlockHead& signBlob, + HapSubSignBlockHead& profileBlob, + HapSubSignBlockHead& propertyBlob) +{ + signBlob.type = HAP_SIGN_BLOB; + signBlob.length = TEST_FILE_BLOCK_LENGTH; + signBlob.offset = sizeof(HapSubSignBlockHead) * TEST_FILE_BLOCK_COUNT; + profileBlob.type = PROFILE_BLOB; + profileBlob.length = TEST_FILE_BLOCK_LENGTH; + profileBlob.offset = signBlob.offset + signBlob.length; + propertyBlob.type = PROPERTY_BLOB; + propertyBlob.length = TEST_FILE_BLOCK_LENGTH; + propertyBlob.offset = profileBlob.offset + profileBlob.length; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/utils/src/hash_utils.cpp b/hapsigntool_cpp/utils/src/hash_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d4f58d05b0311264021e9f117f2327e08ec9a44 --- /dev/null +++ b/hapsigntool_cpp/utils/src/hash_utils.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2024-2024 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 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); + for (int 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; + int32_t num = 0; + while (readLength < length) { + int32_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 (int 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 (int 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/hapsigntool_cpp/utils/src/key_store_helper.cpp b/hapsigntool_cpp/utils/src/key_store_helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b565386331d41106c5539cf88e6c86dd240d3703 --- /dev/null +++ b/hapsigntool_cpp/utils/src/key_store_helper.cpp @@ -0,0 +1,764 @@ +/* + * Copyright (c) 2024-2024 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; + 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, (unsigned char*)"US", -1, -1, 0) + || !X509_NAME_add_entry_by_txt(issuerName, "O", MBSTRING_ASC, (unsigned char*)"My Company", -1, -1, 0) + || !X509_NAME_add_entry_by_txt(issuerName, "CN", MBSTRING_ASC, (unsigned char*)"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)* bags, + 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(&bags, cert); + if (name && !PKCS12_add_friendlyname(bag, name, -1)) { + goto err; + } + + if (keyIdLen && !PKCS12_add_localkeyid(bag, keyId, keyIdLen)) { + goto err; + } + } + + if (bags && !PKCS12_add_safe(safes, bags, certNid, iter, keyStorePwd)) { + goto err; + } + + sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); + bags = NULL; + return RET_OK; +err: + sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); + bags = NULL; + return RET_FAILED; +} + +int KeyStoreHelper::SetPkeyPkcs12(EVP_PKEY* pkey, PKCS12_SAFEBAG* bag, STACK_OF(PKCS12_SAFEBAG)* bags, + 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(&bags, 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 (bags && !PKCS12_add_safe(safes, bags, -1, 0, NULL)) { + goto err; + } + + sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); + bags = NULL; + return RET_OK; +err: + sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); + bags = NULL; + 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) +{ + int r; + if (len >= 0) { + 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/hapsigntool_cpp/utils/src/string_utils.cpp b/hapsigntool_cpp/utils/src/string_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d512422ab683a8d788b37bbcd929f91e871b7345 --- /dev/null +++ b/hapsigntool_cpp/utils/src/string_utils.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2024-2024 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 "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) +{ + for (const std::string& val : strs) { + if (val == str) + return true; + } + return false; +} + +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++; + } + for (auto& ch : del) { + if (ch == slash) { + ch = 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; +} +} // namespace SignatureTools +} // namespace OHOS diff --git a/hapsigntool_cpp/utils/src/verify_cert_openssl_utils.cpp b/hapsigntool_cpp/utils/src/verify_cert_openssl_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dd703042ae7ce81f439bf2d633b6471eebf6a7fc --- /dev/null +++ b/hapsigntool_cpp/utils/src/verify_cert_openssl_utils.cpp @@ -0,0 +1,551 @@ +/* + * Copyright (c) 2024-2024 Huawei Device Co., Ltd.verify_cert_openssl_utils.h + * 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; +constexpr int32_t BUFF_SIZE = 3; + +X509* VerifyCertOpensslUtils::GetX509CertFromPemString(const std::string& pemString) +{ + BIO* pemBio = BIO_new(BIO_s_mem()); + if (pemBio == nullptr) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("BIO_new failed"); + return nullptr; + } + int32_t strLen = static_cast(pemString.size()); + if (BIO_write(pemBio, pemString.c_str(), strLen) != strLen) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("BIO_write failed"); + BIO_free_all(pemBio); + return nullptr; + } + X509* cert = PEM_read_bio_X509(pemBio, nullptr, nullptr, nullptr); + BIO_free_all(pemBio); + return cert; +} + +X509* VerifyCertOpensslUtils::GetX509CertFromBase64String(const std::string& base64String) +{ + std::unique_ptr decodeBuffer = std::make_unique(base64String.size()); + const unsigned char* input = reinterpret_cast(base64String.c_str()); + int32_t len = EVP_DecodeBlock(decodeBuffer.get(), input, base64String.size()); + if (len <= 0) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("base64Decode failed, len: %d", len); + return nullptr; + } + const unsigned char* derBits = decodeBuffer.get(); + X509* cert = d2i_X509(nullptr, &derBits, len); + return cert; +} + +bool VerifyCertOpensslUtils::GetPublickeyBase64FromPemCert(const std::string& certStr, + std::string& publicKey) +{ + X509* cert = GetX509CertFromPemString(certStr); + if (cert == nullptr) { + SIGNATURE_TOOLS_LOGE("GetX509CertFromPemString failed"); + return false; + } + if (!GetPublickeyBase64(cert, publicKey)) { + SIGNATURE_TOOLS_LOGE("X509_get_pubkey failed"); + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + X509_free(cert); + return false; + } + X509_free(cert); + return true; +} + +bool VerifyCertOpensslUtils::GetFingerprintBase64FromPemCert(const std::string& certStr, + std::string& fingerprint) +{ + SIGNATURE_TOOLS_LOGD("GetFingerprintBase64FromPemCert begin"); + X509* cert = GetX509CertFromPemString(certStr); + if (cert == nullptr) { + SIGNATURE_TOOLS_LOGE("GetX509CertFromPemString failed"); + return false; + } + int32_t certLen = i2d_X509(cert, nullptr); + if (certLen <= 0) { + SIGNATURE_TOOLS_LOGE("certLen %d, i2d_X509 failed", certLen); + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + X509_free(cert); + return false; + } + std::unique_ptr derCertificate = std::make_unique(certLen); + unsigned char* derCertificateBackup = derCertificate.get(); + if (i2d_X509(cert, &derCertificateBackup) <= 0) { + SIGNATURE_TOOLS_LOGE("i2d_X509 failed"); + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + X509_free(cert); + return false; + } + SHA256_CTX sha256; + SHA256_Init(&sha256); + SHA256_Update(&sha256, derCertificate.get(), certLen); + unsigned char hash[SHA256_DIGEST_LENGTH]; + SHA256_Final(hash, &sha256); + char buff[BUFF_SIZE] = { 0 }; + for (int32_t index = 0; index < SHA256_DIGEST_LENGTH; ++index) { + if (sprintf_s(buff, sizeof(buff), "%02X", hash[index]) < 0) { + fingerprint.clear(); + SIGNATURE_TOOLS_LOGE("transforms hash string to hexadecimal string failed"); + X509_free(cert); + return false; + } + fingerprint += buff; + } + X509_free(cert); + SIGNATURE_TOOLS_LOGD("GetFingerprintBase64FromPemCert end %s", fingerprint.c_str()); + return true; +} + +bool VerifyCertOpensslUtils::GetPublickeyBase64(const X509* cert, std::string& publicKey) +{ + EVP_PKEY* pkey = X509_get0_pubkey(cert); + if (pkey == nullptr) { + SIGNATURE_TOOLS_LOGE("X509_get0_pubkey failed"); + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + return false; + } + int32_t keyLen = i2d_PublicKey(pkey, nullptr); + if (keyLen <= 0) { + SIGNATURE_TOOLS_LOGE("keyLen %d, i2d_PublicKey failed", keyLen); + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + return false; + } + std::unique_ptr derPublicKey = std::make_unique(keyLen); + int32_t base64KeyLen = CalculateLenAfterBase64Encode(keyLen); + std::unique_ptr base64PublicKey = std::make_unique(base64KeyLen); + unsigned char* derCertificateBackup = derPublicKey.get(); + if (i2d_PublicKey(pkey, &derCertificateBackup) <= 0) { + SIGNATURE_TOOLS_LOGE("i2d_PublicKey failed"); + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + return false; + } + int32_t outLen = EVP_EncodeBlock(base64PublicKey.get(), derPublicKey.get(), keyLen); + publicKey = std::string(reinterpret_cast(base64PublicKey.get()), outLen); + return true; +} + +bool VerifyCertOpensslUtils::GetOrganizationFromPemCert(const std::string& certStr, + std::string& organization) +{ + SIGNATURE_TOOLS_LOGD("GetFingerprintBase64FromPemCert begin"); + X509* cert = GetX509CertFromPemString(certStr); + if (cert == nullptr) { + SIGNATURE_TOOLS_LOGE("GetX509CertFromPemString failed"); + return false; + } + X509_NAME* name = X509_get_subject_name(cert); + GetTextFromX509Name(name, NID_organizationName, organization); + X509_free(cert); + return true; +} +/* +* The length after Base64 encoding is 4/3 of the length before encoding, +* and openssl function will add '\0' to the encoded string. +* So len_after_encode = len_before_encode * 4/3 + 1 +*/ +int32_t VerifyCertOpensslUtils::CalculateLenAfterBase64Encode(int32_t len) +{ + return (len + BASE64_ENCODE_PACKET_LEN - 1) / BASE64_ENCODE_PACKET_LEN + * BASE64_ENCODE_LEN_OF_EACH_GROUP_DATA + 1; +} +bool VerifyCertOpensslUtils::CompareX509Cert(const X509* certA, const std::string& base64Cert) +{ + if (certA == nullptr) { + SIGNATURE_TOOLS_LOGE("certA is nullptr"); + return false; + } + X509* certB = GetX509CertFromPemString(base64Cert); + if (certB == nullptr) { + SIGNATURE_TOOLS_LOGE("generate certB failed"); + return false; + } + bool ret = (X509_cmp(certA, certB) == 0); + X509_free(certB); + return ret; +} + +X509_CRL* VerifyCertOpensslUtils::GetX509CrlFromDerBuffer(const ByteBuffer& crlBuffer, + int32_t offset, int32_t len) +{ + if (crlBuffer.GetBufferPtr() == nullptr) { + SIGNATURE_TOOLS_LOGE("invalid input, crlbuffer is null"); + return nullptr; + } + if ((len <= 0) || (offset < 0) || (crlBuffer.GetCapacity() - len < offset)) { + SIGNATURE_TOOLS_LOGE("invalid input, offset: %d, len: %d", offset, len); + return nullptr; + } + BIO* derBio = BIO_new(BIO_s_mem()); + if (derBio == nullptr) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("BIO_new failed"); + return nullptr; + } + if (BIO_write(derBio, crlBuffer.GetBufferPtr() + offset, len) != len) { + VerifyHapOpensslUtils::GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("BIO_write failed"); + BIO_free_all(derBio); + return nullptr; + } + X509_CRL* crl = d2i_X509_CRL_bio(derBio, nullptr); + BIO_free_all(derBio); + return crl; +} + +void VerifyCertOpensslUtils::WriteX509CrlToStream(std::ofstream& crlFile, X509_CRL* crl) +{ + if (!crlFile.is_open()) { + SIGNATURE_TOOLS_LOGE("fill is not open"); + return; + } + BIO* derBio = BIO_new(BIO_s_mem()); + if (derBio == nullptr) { + SIGNATURE_TOOLS_LOGE("BIO_new failed"); + return; + } + if (crl == nullptr || i2d_X509_CRL_bio(derBio, crl) == 0) { + BIO_free_all(derBio); + SIGNATURE_TOOLS_LOGE("i2d_X509_CRL_bio failed"); + return; + } + int32_t totalLen = 0; + int64_t posStart = crlFile.tellp(); + crlFile.seekp(posStart + sizeof(totalLen)); + char buf[OPENSSL_READ_CRL_LEN_EACH_TIME]; + int32_t readLen = BIO_read(derBio, buf, sizeof(buf)); + int32_t readTime = 0; + while (readLen > 0 && (++readTime < OPENSSL_READ_CRL_MAX_TIME)) { + crlFile.write(buf, readLen); + totalLen += readLen; + readLen = BIO_read(derBio, buf, sizeof(buf)); + } + BIO_free_all(derBio); + int64_t posEnd = crlFile.tellp(); + crlFile.seekp(posStart); + /* write crl data len */ + crlFile.write(reinterpret_cast(&totalLen), sizeof(totalLen)); + crlFile.seekp(posEnd); +} + +void VerifyCertOpensslUtils::GenerateCertSignFromCertStack(STACK_OF(X509)* certs, CertSign& certVisitSign) +{ + if (certs == nullptr) { + return; + } + for (int32_t i = 0; i < sk_X509_num(certs); i++) { + X509* cert = sk_X509_value(certs, i); + if (cert == nullptr) { + continue; + } + certVisitSign[cert] = 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* signCertIssuer = X509_get_issuer_name(cert); + for (auto certPair : certVisitSign) { + if (certPair.second) { + continue; + } + X509* issuerCert = certPair.first; + X509_NAME* issuerCertSubject = X509_get_subject_name(issuerCert); + /* verify sign and issuer */ + if (X509NameCompare(issuerCertSubject, signCertIssuer) && + 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* certIssuer = X509_get_issuer_name(cert); + for (int32_t i = 0; i < sk_X509_CRL_num(crls); i++) { + X509_CRL* crl = sk_X509_CRL_value(crls, i); + if (crl == nullptr) { + continue; + } + X509_NAME* crlIssuer = X509_CRL_get_issuer(crl); + if (X509NameCompare(crlIssuer, certIssuer)) { + return crl; + } + } + 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; +} + +bool VerifyCertOpensslUtils::GetSerialNumberFromX509(const X509* cert, int64_t& certNumber) +{ + if (cert == nullptr) { + SIGNATURE_TOOLS_LOGE("cert is nullptr"); + return false; + } + const ASN1_INTEGER* certSN = X509_get0_serialNumber(cert); + certNumber = ASN1_INTEGER_get(certSN); + SIGNATURE_TOOLS_LOGD("cert number = %" PRId64, certNumber); + return true; +} + +bool VerifyCertOpensslUtils::GetIssuerFromX509Crl(const X509_CRL* crl, std::string& issuer) +{ + if (crl == nullptr) { + SIGNATURE_TOOLS_LOGE("clr is nullptr"); + return false; + } + X509_NAME* name = X509_CRL_get_issuer(crl); + if (name == nullptr) { + SIGNATURE_TOOLS_LOGE("crl issuer nullptr"); + return false; + } + issuer = GetDnToString(name); + return true; +} + +std::string VerifyCertOpensslUtils::GetDnToString(X509_NAME* name) +{ + if (name == nullptr) { + return ""; + } + std::string countryName; + GetTextFromX509Name(name, NID_countryName, countryName); + std::string organizationName; + GetTextFromX509Name(name, NID_organizationName, organizationName); + std::string organizationalUnitName; + GetTextFromX509Name(name, NID_organizationalUnitName, organizationalUnitName); + std::string commonName; + GetTextFromX509Name(name, NID_commonName, commonName); + return "C=" + countryName + ", 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/hapsigntool_cpp/utils/src/verify_hap_openssl_utils.cpp b/hapsigntool_cpp/utils/src/verify_hap_openssl_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..28a16ed84e4ee6217979a23ff4002b0bf6cb1a56 --- /dev/null +++ b/hapsigntool_cpp/utils/src/verify_hap_openssl_utils.cpp @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2024-2024 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.certChains.push_back(certChain); + pkcs7Context.certChains[i].push_back(X509_dup(cert)); + VerifyCertOpensslUtils::ClearCertVisitSign(certVisitSign); + certVisitSign[cert] = true; + if (!VerifyCertChain(pkcs7Context.certChains[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::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.certChains[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::GetPublickeys(const CertChain& signCertChain, + std::vector& SignatureVec) +{ + for (uint32_t i = 0; i < signCertChain.size(); i++) { + if (!GetPublickeyFromCertificate(signCertChain[i], SignatureVec)) { + SIGNATURE_TOOLS_LOGE("%ust Get Publickey failed", i); + return false; + } + } + return !SignatureVec.empty(); +} + +bool VerifyHapOpensslUtils::GetSignatures(const CertChain& signCertChain, + std::vector& SignatureVec) +{ + for (uint32_t i = 0; i < signCertChain.size(); i++) { + if (!GetDerCert(signCertChain[i], SignatureVec)) { + SIGNATURE_TOOLS_LOGE("%ust GetDerCert failed", i); + return false; + } + } + return !SignatureVec.empty(); +} + +bool VerifyHapOpensslUtils::GetDerCert(X509* ptrX509, std::vector& SignatureVec) +{ + if (ptrX509 == nullptr) { + return false; + } + int32_t certLen = i2d_X509(ptrX509, nullptr); + if (certLen <= 0) { + SIGNATURE_TOOLS_LOGE("certLen %d, i2d_X509 failed", certLen); + GetOpensslErrorMessage(); + return false; + } + std::unique_ptr derCertificate = std::make_unique(certLen); + int32_t base64CertLen = VerifyCertOpensslUtils::CalculateLenAfterBase64Encode(certLen); + std::unique_ptr base64Certificate = std::make_unique(base64CertLen); + unsigned char* derCertificateBackup = derCertificate.get(); + if (i2d_X509(ptrX509, &derCertificateBackup) <= 0) { + SIGNATURE_TOOLS_LOGE("i2d_X509 failed"); + GetOpensslErrorMessage(); + return false; + } + /* base64 encode */ + int32_t len = EVP_EncodeBlock(base64Certificate.get(), derCertificate.get(), certLen); + SignatureVec.emplace_back(std::string(reinterpret_cast(base64Certificate.get()), len)); + return true; +} + +bool VerifyHapOpensslUtils::GetPublickeyFromCertificate(const X509* ptrX509, + std::vector& publicKeyVec) +{ + if (ptrX509 == nullptr) { + return false; + } + std::string publicKey; + if (!VerifyCertOpensslUtils::GetPublickeyBase64(ptrX509, publicKey)) { + SIGNATURE_TOOLS_LOGE("GetPublickeyBase64 Failed"); + return false; + } + publicKeyVec.emplace_back(publicKey); + 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; +} + +int32_t VerifyHapOpensslUtils::GetDigestAlgorithmOutputSizeBytes(int32_t nId) +{ + return EVP_MD_size(EVP_get_digestbynid(nId)); +} + +bool VerifyHapOpensslUtils::CheckDigestParameter(const DigestParameter& digestParameter) +{ + if (digestParameter.md == nullptr) { + SIGNATURE_TOOLS_LOGE("md is nullptr"); + return false; + } + if (digestParameter.ptrCtx == nullptr) { + SIGNATURE_TOOLS_LOGE("ptrCtx is nullptr"); + return false; + } + return true; +} + +bool VerifyHapOpensslUtils::DigestInit(const DigestParameter& digestParameter) +{ + if (!CheckDigestParameter(digestParameter)) { + return false; + } + if (EVP_DigestInit(digestParameter.ptrCtx, 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 VerifyHapOpensslUtils::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.ptrCtx, content, len) <= 0) { + GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("EVP_DigestUpdate chunk failed"); + return false; + } + return true; +} + +int32_t VerifyHapOpensslUtils::GetDigest(const DigestParameter& digestParameter, + unsigned char(&out)[EVP_MAX_MD_SIZE]) +{ + uint32_t outLen = 0; + if (!CheckDigestParameter(digestParameter)) { + return outLen; + } + if (EVP_DigestFinal(digestParameter.ptrCtx, out, &outLen) <= 0) { + GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("EVP_DigestFinal failed"); + outLen = 0; + } + return outLen; +} + +int32_t VerifyHapOpensslUtils::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.ptrCtx == nullptr) { + SIGNATURE_TOOLS_LOGE("ptrCtx is nullprt"); + return outLen; + } + if (EVP_DigestInit(digestParameter.ptrCtx, digestParameter.md) <= 0) { + GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("EVP_DigestInit failed"); + return outLen; + } + if (EVP_DigestUpdate(digestParameter.ptrCtx, 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.ptrCtx, optionalBlocks[i].optionalBlockValue.GetBufferPtr(), + chunkLen) <= 0) { + GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("EVP_DigestUpdate %dst optional block failed", i); + return outLen; + } + } + if (EVP_DigestFinal(digestParameter.ptrCtx, out, &outLen) <= 0) { + GetOpensslErrorMessage(); + SIGNATURE_TOOLS_LOGE("EVP_DigestFinal failed"); + outLen = 0; + } + return outLen; +} + +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); + } +} + +int32_t VerifyHapOpensslUtils::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; + } +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/zip/include/central_directory.h b/hapsigntool_cpp/zip/include/central_directory.h new file mode 100644 index 0000000000000000000000000000000000000000..66fc961a74a75a64e242431ccdb1072a5ffe4ab5 --- /dev/null +++ b/hapsigntool_cpp/zip/include/central_directory.h @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2024-2024 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_CENTRAL_DIRECTORY_H +#define SIGNATRUETOOLS_CENTRAL_DIRECTORY_H + +#include + +#include "byte_buffer.h" + +namespace OHOS { +namespace SignatureTools { +/** + * resolve zip CentralDirectory data + * CentralDirectory format for: + * central file header signature 4 bytes (0x02014b50) + * version made by 2 bytes + * version needed to extract 2 bytes + * general purpose bit flag 2 bytes + * compression method 2 bytes + * last mod file time 2 bytes + * last mod file date 2 bytes + * crc-32 4 bytes + * compressed size 4 bytes + * uncompressed size 4 bytes + * file name length 2 bytes + * extra field length 2 bytes + * file comment length 2 bytes + * disk number start 2 bytes + * internal file attributes 2 bytes + * external file attributes 4 bytes + * relative offset of local header 4 bytes + * file name (variable size) + * extra field (variable size) + * file comment (variable size) + */ +class CentralDirectory { +public: + // central directory invariable bytes length + static constexpr int CD_LENGTH = 46; + + // 4 bytes, central directory signature + static constexpr int SIGNATURE = 0x02014b50; + + static bool GetCentralDirectory(ByteBuffer& bf, CentralDirectory* cd); + + std::string ToBytes(); + + static int GetCdLength(); + + static int GetSIGNATURE(); + + short GetVersion(); + + void SetVersion(short version); + + short GetVersionExtra(); + + void SetVersionExtra(short versionExtra); + + short GetFlag(); + + void SetFlag(short flag); + + short GetMethod(); + + void SetMethod(short method); + + short GetLastTime(); + + void SetLastTime(short lastTime); + + short GetLastDate(); + + void SetLastDate(short lastDate); + + int GetCrc32(); + + void SetCrc32(int crc32); + + uint32_t GetCompressedSize(); + + void SetCompressedSize(uint32_t compressedSize); + + uint32_t GetUnCompressedSize(); + + void SetUnCompressedSize(uint32_t unCompressedSize); + + uint16_t GetFileNameLength(); + + void SetFileNameLength(uint16_t fileNameLength); + + uint16_t GetExtraLength(); + + void SetExtraLength(uint16_t extraLength); + + uint16_t GetCommentLength(); + + void SetCommentLength(uint16_t commentLength); + + uint16_t GetDiskNumStart(); + + void SetDiskNumStart(uint16_t diskNumStart); + + short GetInternalFile(); + + void SetInternalFile(short internalFile); + + int GetExternalFile(); + + void SetExternalFile(int externalFile); + + uint32_t GetOffset(); + + void SetOffset(uint32_t offset); + + std::string GetFileName(); + + void SetFileName(const std::string& fileName); + + std::string GetExtraData() const; + + void SetExtraData(const std::string& extraData); + + std::string GetComment(); + + void SetComment(const std::string& comment); + + uint32_t GetLength(); + + void SetLength(uint32_t length); + +private: + static void SetCentralDirectoryValues(ByteBuffer& bf, CentralDirectory* cd); + + /* 2 bytes */ + short m_version = 0; + + /* 2 bytes */ + short m_versionExtra = 0; + + /* 2 bytes */ + short m_flag = 0; + + /* 2 bytes */ + short m_method = 0; + + /* 2 bytes */ + short m_lastTime = 0; + + /* 2 bytes */ + short m_lastDate = 0; + + /* 4 bytes */ + int m_crc32 = 0; + + /* 4 bytes */ + uint32_t m_compressedSize = 0; + + /* 4 bytes */ + uint32_t m_unCompressedSize = 0; + + /* 2 bytes */ + uint16_t m_fileNameLength = 0; + + /* 2 bytes */ + uint16_t m_extraLength = 0; + + /* 2 bytes */ + uint16_t m_commentLength = 0; + + /* 2 bytes */ + uint16_t m_diskNumStart = 0; + + /* 2 bytes */ + short m_internalFile = 0; + + /* 4 bytes */ + int m_externalFile = 0; + + /* 4 bytes */ + uint32_t m_offset = 0; + + /* n bytes */ + std::string m_fileName; + + /* n bytes */ + std::string m_extraData; + + /* n bytes */ + std::string m_comment; + + uint32_t m_length = 0; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_CENTRAL_DIRECTORY_H \ No newline at end of file diff --git a/hapsigntool_cpp/zip/include/data_descriptor.h b/hapsigntool_cpp/zip/include/data_descriptor.h new file mode 100644 index 0000000000000000000000000000000000000000..288e98cb756ced19c83daee9d31f712d9e88e087 --- /dev/null +++ b/hapsigntool_cpp/zip/include/data_descriptor.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024-2024 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_DATA_DESCRIPTOR_H +#define SIGNATRUETOOLS_DATA_DESCRIPTOR_H + +#include "byte_buffer.h" + +namespace OHOS { +namespace SignatureTools { +/** + * resolve zip DataDescriptor data + * DataDescriptor format: + * crc-32 4 bytes + * compressed size 4 bytes + * uncompressed size 4 bytes + */ +class DataDescriptor { +public: + /* DataDescriptor invariable bytes length */ + static constexpr int DES_LENGTH = 16; + + /* 4 bytes , DataDescriptor signature */ + static constexpr int SIGNATURE = 0x08074b50; + + /** + * get Data Descriptor + * + * @param bytes DataDescriptor bytes + * @return DataDescriptor + * @throws ZipException read data descriptor exception + */ + static DataDescriptor* GetDataDescriptor(const std::string& bytes); + + std::string ToBytes(); + + static int GetDesLength(); + + static int GetSIGNATURE(); + + int GetCrc32(); + + void SetCrc32(int crc32); + + uint32_t GetCompressedSize(); + + void SetCompressedSize(uint32_t compressedSize); + + uint32_t GetUnCompressedSize(); + + void SetUnCompressedSize(uint32_t unCompressedSize); + +private: + /* 4 bytes */ + int m_crc32 = 0; + + /* 4 bytes */ + uint32_t m_compressedSize = 0; + + /* 4 bytes */ + uint32_t m_unCompressedSize = 0; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_DATA_DESCRIPTOR_H \ No newline at end of file diff --git a/hapsigntool_cpp/zip/include/endof_central_directory.h b/hapsigntool_cpp/zip/include/endof_central_directory.h new file mode 100644 index 0000000000000000000000000000000000000000..3647cf3938121b2627cf0d9e4293ff823f10b56c --- /dev/null +++ b/hapsigntool_cpp/zip/include/endof_central_directory.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2024-2024 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_ENDOF_CENTRAL_DIRECTORY_H +#define SIGNATRUETOOLS_ENDOF_CENTRAL_DIRECTORY_H + +#include +#include + +namespace OHOS { +namespace SignatureTools { +/** + * resolve zip EndOfCentralDirectory data + * EndOfCentralDirectory format for: + * end of central dir signature 4 bytes (0x06054b50) + * number of this disk 2 bytes + * number of the disk with the + * start of the central directory 2 bytes + * total number of entries in the + * central directory on this disk 2 bytes + * total number of entries in + * the central directory 2 bytes + * size of the central directory 4 bytes + * offset of start of central + * directory with respect to + * the starting disk number 4 bytes + * .ZIP file comment length 2 bytes + * .ZIP file comment (variable size) + */ +class EndOfCentralDirectory { +public: + /* EndOfCentralDirectory invariable bytes length */ + static constexpr int EOCD_LENGTH = 22; + + /* 4 bytes , central directory signature */ + static constexpr int SIGNATURE = 0x06054b50; + + /** + * init End Of Central Directory, default offset is 0 + * + * @param bytes End Of Central Directory bytes + * @return End Of Central Directory + */ + static std::optional GetEOCDByBytes(const std::string& bytes); + + /** + * init End Of Central Directory + * + * @param bytes End Of Central Directory bytes + * @param offset offset + * @return End Of Central Directory + */ + static std::optional GetEOCDByBytes(const std::string& bytes, int offset); + + /** + * change End Of Central Directory to bytes + * + * @return bytes + */ + std::string ToBytes(); + + static int GetEocdLength(); + + static int GetSIGNATURE(); + + uint16_t GetDiskNum(); + + void SetDiskNum(uint16_t diskNum); + + uint16_t GetcDStartDiskNum(); + + void SetcDStartDiskNum(uint16_t cDStartDiskNum); + + uint16_t GetThisDiskCDNum(); + + void SetThisDiskCDNum(uint16_t thisDiskCDNum); + + uint16_t GetcDTotal(); + + void SetcDTotal(uint16_t cDTotal); + + uint32_t GetcDSize(); + + void SetcDSize(uint32_t cDSize); + + uint32_t GetOffset(); + + void SetOffset(uint32_t offset); + + uint16_t GetCommentLength(); + + void SetCommentLength(uint16_t commentLength); + + std::string GetComment(); + + void SetComment(const std::string& comment); + + int GetLength(); + + void SetLength(uint32_t length); + +private: + static void SetEndOfCentralDirectoryValues(ByteBuffer& bf, EndOfCentralDirectory* eocd); + + /* 2 bytes */ + uint16_t m_diskNum = 0; + + /* 2 bytes */ + uint16_t m_cDStartDiskNum = 0; + + /* 2 bytes */ + uint16_t m_thisDiskCDNum = 0; + + /* 2 bytes */ + uint16_t m_cDTotal = 0; + + /* 4 bytes */ + uint32_t m_cDSize = 0; + + /* 4bytes */ + uint32_t m_offset = 0; + + /* 2 bytes */ + uint16_t m_commentLength = 0; + + /* n bytes */ + std::string m_comment; + + uint32_t m_length = 0; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_ENDOF_CENTRAL_DIRECTORY_H \ No newline at end of file diff --git a/hapsigntool_cpp/zip/include/random_access_file_input.h b/hapsigntool_cpp/zip/include/random_access_file_input.h new file mode 100644 index 0000000000000000000000000000000000000000..35222ad8769eeb51184838f44838eaf1b02fc6c2 --- /dev/null +++ b/hapsigntool_cpp/zip/include/random_access_file_input.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024-2024 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_RANDOM_ACCESS_FILE_INPUT_H +#define SIGNATRUETOOLS_RANDOM_ACCESS_FILE_INPUT_H + +#include "file_data_source.h" +#include "random_access_file.h" +#include "signature_tools_log.h" +#include "zip_data_input.h" + +namespace OHOS { +namespace SignatureTools { + +class RandomAccessFileInput : public ZipDataInput { +public: + RandomAccessFileInput(RandomAccessFile& file); + + /** + * Random Access File Zip Data Input + * + * @param file zip file + * @param offset offset + * @param size size + */ + RandomAccessFileInput(RandomAccessFile& file, int64_t offset, int64_t size); + + ~RandomAccessFileInput() + { + } + + int64_t Size() override; + + bool CopyTo(int64_t offset, int size, ByteBuffer& buffer) override; + + ByteBuffer CreateByteBuffer(int64_t offset, int size) override; + + DataSource* Slice(int64_t offset, int64_t size) override; + +private: + static constexpr int MAX_READ_BLOCK_SIZE = 1024 * 1024; + + bool CheckBoundValid(int64_t offset, int64_t size, int64_t sourceSize); + + RandomAccessFile& file; + + const int64_t startIndex; + + const int64_t size; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_RANDOM_ACCESS_FILE_INPUT_H \ No newline at end of file diff --git a/hapsigntool_cpp/zip/include/random_access_file_output.h b/hapsigntool_cpp/zip/include/random_access_file_output.h new file mode 100644 index 0000000000000000000000000000000000000000..d9bc0147a407235cbca2856349ba656fa2f54d01 --- /dev/null +++ b/hapsigntool_cpp/zip/include/random_access_file_output.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024-2024 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_RANDOM_ACCESS_FILE_OUTPUT_H +#define SIGNATRUETOOLS_RANDOM_ACCESS_FILE_OUTPUT_H + +#include + +#include "random_access_file.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { +class RandomAccessFileOutput { +public: + RandomAccessFileOutput(RandomAccessFile* file); + + /** + * RandomAccessFileOutput + * + * @param file zip file + * @param startPosition start position offset + */ + RandomAccessFileOutput(RandomAccessFile* file, int64_t startPosition); + + ~RandomAccessFileOutput() + { + } + + bool Write(ByteBuffer& buffer); + +private: + RandomAccessFile* file; + int64_t position = 0; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_RANDOM_ACCESS_FILE_OUTPUT_H \ No newline at end of file diff --git a/hapsigntool_cpp/zip/include/zip_data_input.h b/hapsigntool_cpp/zip/include/zip_data_input.h new file mode 100644 index 0000000000000000000000000000000000000000..72ca004beccfd4241243f6cf61a0e226e1091f8c --- /dev/null +++ b/hapsigntool_cpp/zip/include/zip_data_input.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2024-2024 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_ZIP_DATA_INPUT_H +#define SIGNATRUETOOLS_ZIP_DATA_INPUT_H + +#include + +#include "byte_buffer.h" +#include "data_source.h" +#include "random_access_file_output.h" + +namespace OHOS { +namespace SignatureTools { + +class ZipDataInput { +public: + virtual ~ZipDataInput() + { + } + + /** + * Get how many bytes are contained in this data input. + * + * @return this data input size + */ + virtual int64_t Size() = 0; + + /** + * Copy the specified data block into the destination ZipDataOutput + * + * @param offset offset index at the ZipDataInput + * @param size size of the data block + * @param buffer the destination ZipDataOutput + * @throws IOException when IO error occurred + */ + virtual bool CopyTo(int64_t offset, int size, ByteBuffer& buffer) = 0; + + /** + * Create a ByteBuffer which contain the specified data block from this ZipDataInput + * + * @param offset offset index at the ZipDataInput + * @param size size of the data block + * @return a ByteBuffer + * @throws IOException when IO error occurred + */ + virtual ByteBuffer CreateByteBuffer(int64_t offset, int size) = 0; + + /** + * Create a new DataSource whose content is shared by this DataSource + * + * @param offset offset index at the DataSource + * @param size size of the data block + * @return new DataSource + */ + virtual DataSource* Slice(int64_t offset, int64_t size) = 0; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_ZIP_DATA_INPUT_H \ No newline at end of file diff --git a/hapsigntool_cpp/zip/include/zip_entry.h b/hapsigntool_cpp/zip/include/zip_entry.h new file mode 100644 index 0000000000000000000000000000000000000000..4e0ba8fa6e8188dfb381eb30183f234f918e8750 --- /dev/null +++ b/hapsigntool_cpp/zip/include/zip_entry.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024-2024 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_ZIP_ENTRY_H +#define SIGNATRUETOOLS_ZIP_ENTRY_H + +#include "central_directory.h" +#include "zip_entry_data.h" + +namespace OHOS { +namespace SignatureTools { +class ZipEntry { +public: + ZipEntry() + { + m_zipEntryData = nullptr; + m_fileEntryInCentralDirectory = nullptr; + } + + ~ZipEntry() + { + delete m_zipEntryData; + delete m_fileEntryInCentralDirectory; + } + + ZipEntryData* GetZipEntryData(); + + void SetZipEntryData(ZipEntryData* zipEntryData); + + CentralDirectory* GetCentralDirectory(); + + void SetCentralDirectory(CentralDirectory* centralDirectory); + + int Alignment(int alignNum); + +private: + bool CalZeroPaddingLengthForEntryExtra(uint16_t& padding); + + bool SetCenterDirectoryNewExtraLength(uint16_t newLength); + + bool SetEntryHeaderNewExtraLength(uint16_t newLength); + + bool GetAlignmentNewExtra(uint16_t newLength, const std::string& old, std::string& res); + + ZipEntryData* m_zipEntryData; + + CentralDirectory* m_fileEntryInCentralDirectory; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_ZIP_ENTRY_H \ No newline at end of file diff --git a/hapsigntool_cpp/zip/include/zip_entry_data.h b/hapsigntool_cpp/zip/include/zip_entry_data.h new file mode 100644 index 0000000000000000000000000000000000000000..658f542136addb37d643b0748b3233a544f36db6 --- /dev/null +++ b/hapsigntool_cpp/zip/include/zip_entry_data.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2024-2024 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_ZIP_ENTRY_DATA_H +#define SIGNATRUETOOLS_ZIP_ENTRY_DATA_H + +#include + +#include "data_descriptor.h" +#include "zip_entry_header.h" + +namespace OHOS { +namespace SignatureTools { + +class ZipEntryData { +public: + /* data descriptor has or not mask */ + static constexpr short HAS_DATA_DESCRIPTOR_MASK = 0x08; + + /* data descriptor has or not flag mask */ + static constexpr short NOT_HAS_DATA_DESCRIPTOR_FLAG = 0; + + ZipEntryData() + { + m_zipEntryHeader = nullptr; + m_dataDescriptor = nullptr; + } + + ~ZipEntryData() + { + delete m_zipEntryHeader; + delete m_dataDescriptor; + } + + ZipEntryHeader* GetZipEntryHeader(); + + /** + * init zip entry by file + * + * @param file zip file + * @param entryOffset entry start offset + * @param fileSize compress file size + * @return zip entry + * @throws IOException read zip exception + */ + static ZipEntryData* GetZipEntry(std::ifstream& input, uint32_t entryOffset, uint32_t fileSize); + + void SetZipEntryHeader(ZipEntryHeader* zipEntryHeader); + + DataDescriptor* GetDataDescriptor(); + + void SetDataDescriptor(DataDescriptor* dataDescriptor); + + uint32_t GetFileOffset(); + + void SetFileOffset(uint32_t fileOffset); + + uint32_t GetFileSize(); + + void SetFileSize(uint32_t fileSize); + + uint32_t GetLength(); + + void SetLength(uint32_t length); + +private: + static bool ReadEntryFileNameAndExtraByOffset(std::ifstream& input, ZipEntryHeader* entryHeader, + uint32_t& offset); + + ZipEntryHeader* m_zipEntryHeader; + + uint32_t m_fileOffset = 0; + + uint32_t m_fileSize = 0; + + DataDescriptor* m_dataDescriptor; + + uint32_t m_length = 0; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_ZIP_ENTRY_DATA_H \ No newline at end of file diff --git a/hapsigntool_cpp/zip/include/zip_entry_header.h b/hapsigntool_cpp/zip/include/zip_entry_header.h new file mode 100644 index 0000000000000000000000000000000000000000..773705bd544816e06bc246433fe93666d9360b63 --- /dev/null +++ b/hapsigntool_cpp/zip/include/zip_entry_header.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2024-2024 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_ZIP_ENTRY_HEADER_H +#define SIGNATRUETOOLS_ZIP_ENTRY_HEADER_H + +#include + +#include "byte_buffer.h" + +namespace OHOS { +namespace SignatureTools { +/** + * resolve zip ZipEntryHeader data + * end of central dir signature 4 bytes (0x06054b50) + * number of this disk 2 bytes + * number of the disk with the + * start of the central directory 2 bytes + * total number of entries in the + * central directory on this disk 2 bytes + * total number of entries in + * the central directory 2 bytes + * size of the central directory 4 bytes + * offset of start of central + * directory with respect to + * the starting disk number 4 bytes + * .ZIP file comment length 2 bytes + * .ZIP file comment (variable size) + */ +class ZipEntryHeader { +public: + /* ZipEntryHeader invariable bytes length */ + static constexpr int HEADER_LENGTH = 30; + + /* 4 bytes , entry header signature */ + static constexpr int SIGNATURE = 0x04034b50; + + /** + * get Zip Entry Header + * + * @param bytes ZipEntryHeader bytes + * @return ZipEntryHeader + * @throws ZipException read entry header exception + */ + static ZipEntryHeader* GetZipEntryHeader(const std::string& bytes); + + void ReadFileName(const std::string& bytes); + + void ReadExtra(const std::string& bytes); + + std::string ToBytes(); + + static int GetHeaderLength(); + + static int GetSIGNATURE(); + + short GetVersion(); + + void SetVersion(short version); + + short GetFlag(); + + void SetFlag(short flag); + + short GetMethod(); + + void SetMethod(short method); + + short GetLastTime(); + + void SetLastTime(short lastTime); + + short GetLastDate(); + + void SetLastDate(short lastDate); + + int GetCrc32(); + + void SetCrc32(int crc32); + + uint32_t GetCompressedSize(); + + void SetCompressedSize(uint32_t compressedSize); + + uint32_t GetUnCompressedSize(); + + void SetUnCompressedSize(uint32_t unCompressedSize); + + uint16_t GetFileNameLength(); + + void SetFileNameLength(uint16_t fileNameLength); + + uint16_t GetExtraLength(); + + void SetExtraLength(uint16_t extraLength); + + std::string GetFileName() const; + + void SetFileName(const std::string& fileName); + + std::string GetExtraData() const; + + void SetExtraData(const std::string& extraData); + + uint32_t GetLength(); + + void SetLength(uint32_t length); + +private: + /* 2 bytes */ + short m_version = 0; + + /* 2 bytes */ + short m_flag = 0; + + /* 2 bytes */ + short m_method = 0; + + /* 2 bytes */ + short m_lastTime = 0; + + /* 2 bytes */ + short m_lastDate = 0; + + /* 4 bytes */ + int m_crc32 = 0; + + /* 4 bytes */ + uint32_t m_compressedSize = 0; + + /* 4 bytes */ + uint32_t m_unCompressedSize = 0; + + /* 2 bytes */ + uint16_t m_fileNameLength = 0; + + /* 2 bytes */ + uint16_t m_extraLength = 0; + + /* n bytes */ + std::string m_fileName; + + /* n bytes */ + std::string m_extraData; + + uint32_t m_length = 0; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_ZIP_ENTRY_HEADER_H \ No newline at end of file diff --git a/hapsigntool_cpp/zip/include/zip_signer.h b/hapsigntool_cpp/zip/include/zip_signer.h new file mode 100644 index 0000000000000000000000000000000000000000..e2f2df1eb68887470fc25091b855fcf0bef177fb --- /dev/null +++ b/hapsigntool_cpp/zip/include/zip_signer.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2024-2024 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_ZIP_SIGNER_H +#define SIGNATRUETOOLS_ZIP_SIGNER_H + +#include +#include +#include +#include + +#include "endof_central_directory.h" +#include "signature_tools_log.h" +#include "zip_entry.h" + +namespace OHOS { +namespace SignatureTools { +class ZipSigner { +public: + /* file is uncompress file flag */ + static constexpr int FILE_UNCOMPRESS_METHOD_FLAG = 0; + + /* max comment length */ + static constexpr int MAX_COMMENT_LENGTH = 65535; + + ZipSigner() + { + m_endOfCentralDirectory = nullptr; + } + + ~ZipSigner() + { + delete m_endOfCentralDirectory; + for (auto& zipEntry : m_zipEntries) { + delete zipEntry; + } + } + + bool Init(std::ifstream& inputFile); + + /** + * output zip to zip file + * + * @param outFile file path + */ + bool ToFile(std::ifstream& input, std::ofstream& output); + + /** + * alignment uncompress entry + * + * @param alignment int alignment + */ + void Alignment(int alignment); + + void RemoveSignBlock(); + + std::vector& GetZipEntries(); + + void SetZipEntries(const std::vector& zipEntries); + + uint32_t GetSigningOffset(); + + void SetSigningOffset(uint32_t signingOffset); + + std::string GetSigningBlock(); + + void SetSigningBlock(const std::string& signingBlock); + + uint32_t GetCDOffset(); + + void SetCDOffset(uint32_t cDOffset); + + uint32_t GetEOCDOffset(); + + void SetEOCDOffset(uint32_t eOCDOffset); + + EndOfCentralDirectory* GetEndOfCentralDirectory(); + + void SetEndOfCentralDirectory(EndOfCentralDirectory* endOfCentralDirectory); + +private: + EndOfCentralDirectory* GetZipEndOfCentralDirectory(std::ifstream& input); + + bool GetZipCentralDirectory(std::ifstream& input); + + std::string GetSigningBlock(std::ifstream& input); + + bool GetZipEntries(std::ifstream& input); + + /* sort uncompress entry in the front. */ + void Sort(); + + void ResetOffset(); + + std::vector m_zipEntries; + + uint32_t m_signingOffset = 0; + + std::string m_signingBlock; + + uint32_t m_cDOffset = 0; + + uint32_t m_eOCDOffset = 0; + + EndOfCentralDirectory* m_endOfCentralDirectory; +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_ZIP_SIGNER_H diff --git a/hapsigntool_cpp/zip/include/zip_utils.h b/hapsigntool_cpp/zip/include/zip_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..ee515de176b679c89f6ff05c9c77599570ef3465 --- /dev/null +++ b/hapsigntool_cpp/zip/include/zip_utils.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024-2024 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_ZIP_UTILS_H +#define SIGNATRUETOOLS_ZIP_UTILS_H + +#include +#include + +#include "signature_tools_log.h" +#include "zip_data_input.h" + +namespace OHOS { +namespace SignatureTools { +class ZipUtils { +public: + ZipUtils() = delete; + /** + * set offset value of Central Directory to End of Central Directory Record. + * + * @param eocd buffer of End of Central Directory Record. + * @param offset offset value of Central Directory. + */ + static bool SetCentralDirectoryOffset(ByteBuffer& eocd, int64_t offset); + +private: + static constexpr int ZIP_CENTRAL_DIR_OFFSET_IN_EOCD = 16; + + static constexpr int64_t UINT32_MAX_VALUE = 0xffffffffLL; + + static bool SetUInt32ToBuffer(ByteBuffer& buffer, int offset, int64_t value); +}; +} // namespace SignatureTools +} // namespace OHOS +#endif // SIGNATRUETOOLS_ZIP_UTILS_H diff --git a/hapsigntool_cpp/zip/signature_tools_zip.gni b/hapsigntool_cpp/zip/signature_tools_zip.gni new file mode 100644 index 0000000000000000000000000000000000000000..a45b745b015548ceafd64a4f2cea00e73913977f --- /dev/null +++ b/hapsigntool_cpp/zip/signature_tools_zip.gni @@ -0,0 +1,28 @@ +# Copyright (c) 2024 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_zip_include = [ "${signature_tools_zip}/include" ] + +signature_tools_zip_src = [ + "${signature_tools_zip}/src/central_directory.cpp", + "${signature_tools_zip}/src/data_descriptor.cpp", + "${signature_tools_zip}/src/endof_central_directory.cpp", + "${signature_tools_zip}/src/random_access_file_input.cpp", + "${signature_tools_zip}/src/random_access_file_output.cpp", + "${signature_tools_zip}/src/zip_entry.cpp", + "${signature_tools_zip}/src/zip_entry_data.cpp", + "${signature_tools_zip}/src/zip_entry_header.cpp", + "${signature_tools_zip}/src/zip_signer.cpp", + "${signature_tools_zip}/src/zip_utils.cpp", +] diff --git a/hapsigntool_cpp/zip/src/central_directory.cpp b/hapsigntool_cpp/zip/src/central_directory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b7b1661d4fcc609a9d5b1efe6e6391db1951a2e5 --- /dev/null +++ b/hapsigntool_cpp/zip/src/central_directory.cpp @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2024-2024 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 "central_directory.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { +bool CentralDirectory::GetCentralDirectory(ByteBuffer& bf, CentralDirectory* cd) +{ + int signatureValue; + bf.GetInt32(signatureValue); + if (signatureValue != SIGNATURE) { + SIGNATURE_TOOLS_LOGE("find zip central directory failed"); + return false; + } + + SetCentralDirectoryValues(bf, cd); + + uint16_t fileNameLength = cd->GetFileNameLength(); + if (fileNameLength > 0) { + std::string readFileName(fileNameLength, 0); + bf.GetData(&readFileName[0], fileNameLength); + cd->SetFileName(readFileName); + } + uint16_t extraLength = cd->GetExtraLength(); + if (extraLength > 0) { + std::string extra(extraLength, 0); + bf.GetData(&extra[0], extraLength); + cd->SetExtraData(extra); + } + uint16_t commentLength = cd->GetCommentLength(); + if (commentLength > 0) { + std::string readComment(commentLength, 0); + bf.GetData(&readComment[0], commentLength); + cd->SetComment(readComment); + } + cd->SetLength(CD_LENGTH + fileNameLength + extraLength + commentLength); + + return true; +} + +void CentralDirectory::SetCentralDirectoryValues(ByteBuffer& bf, CentralDirectory* cd) +{ + int16_t centralDirectoryInt16Value; + bf.GetInt16(centralDirectoryInt16Value); + cd->SetVersion(centralDirectoryInt16Value); + + bf.GetInt16(centralDirectoryInt16Value); + cd->SetVersionExtra(centralDirectoryInt16Value); + + bf.GetInt16(centralDirectoryInt16Value); + cd->SetFlag(centralDirectoryInt16Value); + + bf.GetInt16(centralDirectoryInt16Value); + cd->SetMethod(centralDirectoryInt16Value); + + bf.GetInt16(centralDirectoryInt16Value); + cd->SetLastTime(centralDirectoryInt16Value); + + bf.GetInt16(centralDirectoryInt16Value); + cd->SetLastDate(centralDirectoryInt16Value); + + int32_t centralDirectoryInt32Value; + bf.GetInt32(centralDirectoryInt32Value); + cd->SetCrc32(centralDirectoryInt32Value); + + uint32_t centralDirectoryUInt32Value; + bf.GetUInt32(centralDirectoryUInt32Value); + cd->SetCompressedSize(centralDirectoryUInt32Value); + + bf.GetUInt32(centralDirectoryUInt32Value); + cd->SetUnCompressedSize(centralDirectoryUInt32Value); + + uint16_t centralDirectoryUInt16Value; + bf.GetUInt16(centralDirectoryUInt16Value); + cd->SetFileNameLength(centralDirectoryUInt16Value); + + bf.GetUInt16(centralDirectoryUInt16Value); + cd->SetExtraLength(centralDirectoryUInt16Value); + + bf.GetUInt16(centralDirectoryUInt16Value); + cd->SetCommentLength(centralDirectoryUInt16Value); + + bf.GetUInt16(centralDirectoryUInt16Value); + cd->SetDiskNumStart(centralDirectoryUInt16Value); + + bf.GetInt16(centralDirectoryInt16Value); + cd->SetInternalFile(centralDirectoryInt16Value); + + bf.GetInt32(centralDirectoryInt32Value); + cd->SetExternalFile(centralDirectoryInt32Value); + + bf.GetUInt32(centralDirectoryUInt32Value); + cd->SetOffset(centralDirectoryUInt32Value); +} + +std::string CentralDirectory::ToBytes() +{ + ByteBuffer bf(m_length); + bf.PutInt32(SIGNATURE); + bf.PutInt16(m_version); + bf.PutInt16(m_versionExtra); + bf.PutInt16(m_flag); + bf.PutInt16(m_method); + bf.PutInt16(m_lastTime); + bf.PutInt16(m_lastDate); + bf.PutInt32(m_crc32); + bf.PutUInt32(m_compressedSize); + bf.PutUInt32(m_unCompressedSize); + bf.PutUInt16(m_fileNameLength); + bf.PutUInt16(m_extraLength); + bf.PutUInt16(m_commentLength); + bf.PutUInt16(m_diskNumStart); + bf.PutInt16(m_internalFile); + bf.PutInt32(m_externalFile); + bf.PutUInt32(m_offset); + + if (m_fileNameLength > 0) { + bf.PutData(m_fileName.c_str(), m_fileName.size()); + } + if (m_extraLength > 0) { + bf.PutData(m_extraData.c_str(), m_extraData.size()); + } + if (m_commentLength > 0) { + bf.PutData(m_extraData.c_str(), m_extraData.size()); + } + + return bf.ToString(); +} + +int CentralDirectory::GetCdLength() +{ + return CD_LENGTH; +} + +int CentralDirectory::GetSIGNATURE() +{ + return SIGNATURE; +} + +short CentralDirectory::GetVersion() +{ + return m_version; +} + +void CentralDirectory::SetVersion(short version) +{ + m_version = version; +} + +short CentralDirectory::GetVersionExtra() +{ + return m_versionExtra; +} + +void CentralDirectory::SetVersionExtra(short versionExtra) +{ + m_versionExtra = versionExtra; +} + +short CentralDirectory::GetFlag() +{ + return m_flag; +} + +void CentralDirectory::SetFlag(short flag) +{ + m_flag = flag; +} + +short CentralDirectory::GetMethod() +{ + return m_method; +} + +void CentralDirectory::SetMethod(short method) +{ + m_method = method; +} + +short CentralDirectory::GetLastTime() +{ + return m_lastTime; +} + +void CentralDirectory::SetLastTime(short lastTime) +{ + m_lastTime = lastTime; +} + +short CentralDirectory::GetLastDate() +{ + return m_lastDate; +} + +void CentralDirectory::SetLastDate(short lastDate) +{ + m_lastDate = lastDate; +} + +int CentralDirectory::GetCrc32() +{ + return m_crc32; +} + +void CentralDirectory::SetCrc32(int crc32) +{ + m_crc32 = crc32; +} + +uint32_t CentralDirectory::GetCompressedSize() +{ + return m_compressedSize; +} + +void CentralDirectory::SetCompressedSize(uint32_t compressedSize) +{ + m_compressedSize = compressedSize; +} + +uint32_t CentralDirectory::GetUnCompressedSize() +{ + return m_unCompressedSize; +} + +void CentralDirectory::SetUnCompressedSize(uint32_t unCompressedSize) +{ + m_unCompressedSize = unCompressedSize; +} + +uint16_t CentralDirectory::GetFileNameLength() +{ + return m_fileNameLength; +} + +void CentralDirectory::SetFileNameLength(uint16_t fileNameLength) +{ + m_fileNameLength = fileNameLength; +} + +uint16_t CentralDirectory::GetExtraLength() +{ + return m_extraLength; +} + +void CentralDirectory::SetExtraLength(uint16_t extraLength) +{ + m_extraLength = extraLength; +} + +uint16_t CentralDirectory::GetCommentLength() +{ + return m_commentLength; +} + +void CentralDirectory::SetCommentLength(uint16_t commentLength) +{ + m_commentLength = commentLength; +} + +uint16_t CentralDirectory::GetDiskNumStart() +{ + return m_diskNumStart; +} + +void CentralDirectory::SetDiskNumStart(uint16_t diskNumStart) +{ + m_diskNumStart = diskNumStart; +} + +short CentralDirectory::GetInternalFile() +{ + return m_internalFile; +} + +void CentralDirectory::SetInternalFile(short internalFile) +{ + m_internalFile = internalFile; +} + +int CentralDirectory::GetExternalFile() +{ + return m_externalFile; +} + +void CentralDirectory::SetExternalFile(int externalFile) +{ + m_externalFile = externalFile; +} + +uint32_t CentralDirectory::GetOffset() +{ + return m_offset; +} + +void CentralDirectory::SetOffset(uint32_t offset) +{ + m_offset = offset; +} + +std::string CentralDirectory::GetFileName() +{ + return m_fileName; +} + +void CentralDirectory::SetFileName(const std::string& fileName) +{ + m_fileName = fileName; +} + +std::string CentralDirectory::GetExtraData() const +{ + return m_extraData; +} + +void CentralDirectory::SetExtraData(const std::string& extraData) +{ + m_extraData = extraData; +} + +std::string CentralDirectory::GetComment() +{ + return m_comment; +} + +void CentralDirectory::SetComment(const std::string& comment) +{ + m_comment = comment; +} + +uint32_t CentralDirectory::GetLength() +{ + return m_length; +} + +void CentralDirectory::SetLength(uint32_t length) +{ + m_length = length; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/zip/src/data_descriptor.cpp b/hapsigntool_cpp/zip/src/data_descriptor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0c27de8f8d8a273087b562e9e8355014d473f694 --- /dev/null +++ b/hapsigntool_cpp/zip/src/data_descriptor.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024-2024 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 "data_descriptor.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { +DataDescriptor* DataDescriptor::GetDataDescriptor(const std::string& bytes) +{ + if (bytes.size() != DES_LENGTH) { + SIGNATURE_TOOLS_LOGE("read Data Descriptor failed"); + return nullptr; + } + + ByteBuffer bf(bytes.c_str(), bytes.size()); + + DataDescriptor* data = new DataDescriptor(); + int signValue; + bf.GetInt32(signValue); + if (signValue != SIGNATURE) { + delete data; + SIGNATURE_TOOLS_LOGE("read Data Descriptor failed"); + return nullptr; + } + int crc2Value; + bf.GetInt32(crc2Value); + data->SetCrc32(crc2Value); + + uint32_t dataDescUInt32Value; + bf.GetUInt32(dataDescUInt32Value); + data->SetCompressedSize(dataDescUInt32Value); + + bf.GetUInt32(dataDescUInt32Value); + data->SetUnCompressedSize(dataDescUInt32Value); + + return data; +} + +std::string DataDescriptor::ToBytes() +{ + ByteBuffer bf(DES_LENGTH); + bf.PutInt32(SIGNATURE); + bf.PutInt32(m_crc32); + bf.PutUInt32(m_compressedSize); + bf.PutUInt32(m_unCompressedSize); + + return bf.ToString(); +} + +int DataDescriptor::GetDesLength() +{ + return DES_LENGTH; +} + +int DataDescriptor::GetSIGNATURE() +{ + return SIGNATURE; +} + +int DataDescriptor::GetCrc32() +{ + return m_crc32; +} + +void DataDescriptor::SetCrc32(int crc32) +{ + m_crc32 = crc32; +} + +uint32_t DataDescriptor::GetCompressedSize() +{ + return m_compressedSize; +} + +void DataDescriptor::SetCompressedSize(uint32_t compressedSize) +{ + m_compressedSize = compressedSize; +} + +uint32_t DataDescriptor::GetUnCompressedSize() +{ + return m_unCompressedSize; +} + +void DataDescriptor::SetUnCompressedSize(uint32_t unCompressedSize) +{ + m_unCompressedSize = unCompressedSize; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/zip/src/endof_central_directory.cpp b/hapsigntool_cpp/zip/src/endof_central_directory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d869e6565c17bc63f96371ada374465bb0a932cf --- /dev/null +++ b/hapsigntool_cpp/zip/src/endof_central_directory.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2024-2024 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 "byte_buffer.h" +#include "endof_central_directory.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { +std::optional EndOfCentralDirectory::GetEOCDByBytes(const std::string& bytes) +{ + return GetEOCDByBytes(bytes, 0); +} + +std::optional EndOfCentralDirectory::GetEOCDByBytes(const std::string& bytes, int offset) +{ + EndOfCentralDirectory* eocd = new EndOfCentralDirectory(); + int remainingDataLen = bytes.size() - offset; + if (remainingDataLen < EOCD_LENGTH) { + delete eocd; + SIGNATURE_TOOLS_LOGE("remainingDataLen is less than EOCD_LENGTH, remainingDataLen: %d, " + "EOCD_LENGTH: %d", remainingDataLen, EOCD_LENGTH); + return std::nullopt; + } + + ByteBuffer bf(bytes.c_str(), bytes.size()); + + int signValue; + bf.GetInt32(signValue); + if (signValue != SIGNATURE) { + delete eocd; + return std::nullopt; + } + + SetEndOfCentralDirectoryValues(bf, eocd); + + uint16_t commentLength = eocd->GetCommentLength(); + if (bf.Remaining() != commentLength) { + delete eocd; + SIGNATURE_TOOLS_LOGE("bf.Remaining() is not equal to commentLength, bf.Remaining(): %d, " + "commentLength: %" PRIu16, bf.Remaining(), commentLength); + return std::nullopt; + } + if (commentLength > 0) { + std::string readComment(commentLength, 0); + bf.GetData(&readComment[0], commentLength); + eocd->SetComment(readComment); + } + eocd->SetLength(EOCD_LENGTH + commentLength); + if (bf.Remaining() != 0) { + delete eocd; + SIGNATURE_TOOLS_LOGE("bf.Remaining() is not equal to 0, bf.Remaining(): %d", bf.Remaining()); + return std::nullopt; + } + return std::make_optional(eocd); +} + +void EndOfCentralDirectory::SetEndOfCentralDirectoryValues(ByteBuffer& bf, EndOfCentralDirectory* eocd) +{ + uint16_t eocdUInt16Value = 0; + bf.GetUInt16(eocdUInt16Value); + eocd->SetDiskNum(eocdUInt16Value); + + bf.GetUInt16(eocdUInt16Value); + eocd->SetcDStartDiskNum(eocdUInt16Value); + + bf.GetUInt16(eocdUInt16Value); + eocd->SetThisDiskCDNum(eocdUInt16Value); + + bf.GetUInt16(eocdUInt16Value); + eocd->SetcDTotal(eocdUInt16Value); + + uint32_t eocdUInt32Value; + bf.GetUInt32(eocdUInt32Value); + eocd->SetcDSize(eocdUInt32Value); + + bf.GetUInt32(eocdUInt32Value); + eocd->SetOffset(eocdUInt32Value); + + bf.GetUInt16(eocdUInt16Value); + eocd->SetCommentLength(eocdUInt16Value); +} + +std::string EndOfCentralDirectory::ToBytes() +{ + ByteBuffer bf(m_length); + + bf.PutInt32(SIGNATURE); + bf.PutUInt16(m_diskNum); + bf.PutUInt16(m_cDStartDiskNum); + bf.PutUInt16(m_thisDiskCDNum); + bf.PutUInt16(m_cDTotal); + bf.PutUInt32(m_cDSize); + bf.PutUInt32(m_offset); + bf.PutUInt16(m_commentLength); + + if (m_commentLength > 0) { + bf.PutData(m_comment.data(), m_comment.size()); + } + + return bf.ToString(); +} + +int EndOfCentralDirectory::GetEocdLength() +{ + return EOCD_LENGTH; +} + +int EndOfCentralDirectory::GetSIGNATURE() +{ + return SIGNATURE; +} + +uint16_t EndOfCentralDirectory::GetDiskNum() +{ + return m_diskNum; +} + +void EndOfCentralDirectory::SetDiskNum(uint16_t diskNum) +{ + m_diskNum = diskNum; +} + +uint16_t EndOfCentralDirectory::GetcDStartDiskNum() +{ + return m_cDStartDiskNum; +} + +void EndOfCentralDirectory::SetcDStartDiskNum(uint16_t cDStartDiskNum) +{ + m_cDStartDiskNum = cDStartDiskNum; +} + +uint16_t EndOfCentralDirectory::GetThisDiskCDNum() +{ + return m_thisDiskCDNum; +} + +void EndOfCentralDirectory::SetThisDiskCDNum(uint16_t thisDiskCDNum) +{ + m_thisDiskCDNum = thisDiskCDNum; +} + +uint16_t EndOfCentralDirectory::GetcDTotal() +{ + return m_cDTotal; +} + +void EndOfCentralDirectory::SetcDTotal(uint16_t cDTotal) +{ + m_cDTotal = cDTotal; +} + +uint32_t EndOfCentralDirectory::GetcDSize() +{ + return m_cDSize; +} + +void EndOfCentralDirectory::SetcDSize(uint32_t cDSize) +{ + m_cDSize = cDSize; +} + +uint32_t EndOfCentralDirectory::GetOffset() +{ + return m_offset; +} + +void EndOfCentralDirectory::SetOffset(uint32_t offset) +{ + m_offset = offset; +} + +uint16_t EndOfCentralDirectory::GetCommentLength() +{ + return m_commentLength; +} + +void EndOfCentralDirectory::SetCommentLength(uint16_t commentLength) +{ + m_commentLength = commentLength; +} + +std::string EndOfCentralDirectory::GetComment() +{ + return m_comment; +} + +void EndOfCentralDirectory::SetComment(const std::string& comment) +{ + m_comment = comment; +} + +int EndOfCentralDirectory::GetLength() +{ + return m_length; +} + +void EndOfCentralDirectory::SetLength(uint32_t length) +{ + m_length = length; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/zip/src/random_access_file_input.cpp b/hapsigntool_cpp/zip/src/random_access_file_input.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b05817c957d791b6a63e24fef1604cefad45a3a2 --- /dev/null +++ b/hapsigntool_cpp/zip/src/random_access_file_input.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2024-2024 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 + +#include "random_access_file_input.h" + +namespace OHOS { +namespace SignatureTools { +RandomAccessFileInput::RandomAccessFileInput(RandomAccessFile& file) : file(file), + startIndex(0), size(-1) +{ +} + +RandomAccessFileInput::RandomAccessFileInput(RandomAccessFile& file, int64_t offset, int64_t size) + : file(file), startIndex(offset), size(size) +{ + if (offset < 0) { + SIGNATURE_TOOLS_LOGE("out of range: offset %" PRId64, offset); + return; + } + if (size < 0) { + SIGNATURE_TOOLS_LOGE("out of range: size %" PRId64, size); + return; + } +} + +int64_t RandomAccessFileInput::Size() +{ + if (size == -1) { + return file.GetLength(); + } + return size; +} + +bool RandomAccessFileInput::CopyTo(int64_t offset, int size, ByteBuffer& buffer) +{ + int64_t srcSize = Size(); + if (!CheckBoundValid(offset, size, srcSize)) { + return false; + } + if (size == 0) { + SIGNATURE_TOOLS_LOGE("Copy size is equal to 0"); + return false; + } + if (size > buffer.Remaining()) { + SIGNATURE_TOOLS_LOGE("The length size passed in is greater than the reserved length of ByteBuffer"); + return false; + } + int64_t offsetInFile = startIndex + offset; + int remaining = size; + int originalLimit = buffer.GetLimit(); + + buffer.SetLimit(buffer.GetPosition() + size); + int64_t readSize; + while (remaining > 0) { + { + std::mutex tmpMutex; + std::scoped_lock lock(tmpMutex); + readSize = file.ReadFileFullyFromOffset(buffer, offsetInFile); + } + offsetInFile += readSize; + remaining -= readSize; + } + int cap = buffer.GetCapacity(); + buffer.SetPosition(cap); + buffer.SetLimit(originalLimit); + return true; +} + +ByteBuffer RandomAccessFileInput::CreateByteBuffer(int64_t offset, int size) +{ + ByteBuffer byteBuffer; + if (size < 0) { + SIGNATURE_TOOLS_LOGE("IndexOutOfBounds: The created ByteBuffer size %d is less than 0", size); + return byteBuffer; + } + + byteBuffer.SetCapacity(size); + if (!CopyTo(offset, size, byteBuffer)) { + byteBuffer.SetCapacity(0); + return byteBuffer; + } + + return byteBuffer.Flip(); +} + +DataSource* RandomAccessFileInput::Slice(int64_t offset, int64_t size) +{ + int64_t srcSize = Size(); + if (!CheckBoundValid(offset, size, srcSize)) { + return nullptr; + } + if (offset == 0 && size == srcSize) { + SIGNATURE_TOOLS_LOGI("offset: 0, size: %" PRId64 ", it will return itself", size); + return new FileDataSource(file, startIndex, size, 0); + } + return new FileDataSource(file, offset, size, 0); +} + +bool RandomAccessFileInput::CheckBoundValid(int64_t offset, int64_t size, int64_t sourceSize) +{ + if (offset < 0) { + SIGNATURE_TOOLS_LOGE("out of range: offset %" PRId64, offset); + return false; + } + if (size < 0) { + SIGNATURE_TOOLS_LOGE("out of range: size %" PRId64, size); + return false; + } + if (offset > sourceSize) { + SIGNATURE_TOOLS_LOGE("out of range: offset %" PRId64 " is greater than sourceSize %" PRId64, + offset, sourceSize); + return false; + } + int64_t endOffset = offset + size; + if (endOffset < offset) { + SIGNATURE_TOOLS_LOGE("out of range: offset %" PRId64 " add size %" PRId64 " is overflow", + offset, size); + return false; + } + if (endOffset > sourceSize) { + SIGNATURE_TOOLS_LOGE("out of range: offset %" PRId64 " add size %" PRId64 " is greater than " + "sourceSize %" PRId64, offset, size, sourceSize); + return false; + } + return true; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/zip/src/random_access_file_output.cpp b/hapsigntool_cpp/zip/src/random_access_file_output.cpp new file mode 100644 index 0000000000000000000000000000000000000000..411257a512e2c89ad03c275d50b662ad6758ea56 --- /dev/null +++ b/hapsigntool_cpp/zip/src/random_access_file_output.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024-2024 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 "signature_tools_log.h" +#include "random_access_file_output.h" + +namespace OHOS { +namespace SignatureTools { +RandomAccessFileOutput::RandomAccessFileOutput(RandomAccessFile* file) + : RandomAccessFileOutput(file, 0) +{ +} + +RandomAccessFileOutput::RandomAccessFileOutput(RandomAccessFile* file, int64_t startPosition) + : file(file) +{ + if (startPosition < 0) { + SIGNATURE_TOOLS_LOGE("invalide start position: %" PRId64, startPosition); + return; + } + position = startPosition; +} + +bool RandomAccessFileOutput::Write(ByteBuffer& buffer) +{ + int length = buffer.GetCapacity(); + if (length == 0) { + return false; + } + { + std::mutex tmpMutex; + std::scoped_lock lock(tmpMutex); + if (file->WriteToFile(buffer, position, length) < 0) { + PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "write from ByteBuffer to RandomAccessFile failed"); + return false; + } + position += length; + } + return true; +} +} // namespace SignatureTools +} // namespace OHOS diff --git a/hapsigntool_cpp/zip/src/zip_entry.cpp b/hapsigntool_cpp/zip/src/zip_entry.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0066ea98f7012b46fac9da1c350b0fb6ff032ec8 --- /dev/null +++ b/hapsigntool_cpp/zip/src/zip_entry.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2024-2024 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 "signature_tools_log.h" +#include "zip_entry.h" + +namespace OHOS { +namespace SignatureTools { +int ZipEntry::Alignment(int alignNum) +{ + /* if cd extra len bigger than entry extra len, make cd and entry extra length equals */ + if (alignNum == 0) { + return -1; + } + uint16_t padding = 0; + if (!CalZeroPaddingLengthForEntryExtra(padding)) { + return -1; + } + uint32_t remainder = (m_zipEntryData->GetZipEntryHeader()->GetLength() + + m_fileEntryInCentralDirectory->GetOffset()) % alignNum; + if (remainder == 0) { + return padding; + } + int add = alignNum - remainder; + uint16_t newExtraLength = m_zipEntryData->GetZipEntryHeader()->GetExtraLength() + add; + static constexpr int MAX_UNSIGNED_SHORT_VALUE = 0xFFFF; + if (newExtraLength > MAX_UNSIGNED_SHORT_VALUE) { + SIGNATURE_TOOLS_LOGE("can not align %s", m_zipEntryData->GetZipEntryHeader()->GetFileName().c_str()); + return -1; + } + SetEntryHeaderNewExtraLength(newExtraLength); + SetCenterDirectoryNewExtraLength(newExtraLength); + + return add; +} + +bool ZipEntry::CalZeroPaddingLengthForEntryExtra(uint16_t& padding) +{ + uint16_t entryExtraLen = m_zipEntryData->GetZipEntryHeader()->GetExtraLength(); + uint16_t cdExtraLen = m_fileEntryInCentralDirectory->GetExtraLength(); + if (cdExtraLen > entryExtraLen) { + if (!SetEntryHeaderNewExtraLength(cdExtraLen)) { + return false; + } + padding = cdExtraLen - entryExtraLen; + } + if (cdExtraLen < entryExtraLen) { + if (!SetCenterDirectoryNewExtraLength(entryExtraLen)) { + return false; + } + padding = entryExtraLen - cdExtraLen; + } + return true; +} + +bool ZipEntry::SetCenterDirectoryNewExtraLength(uint16_t newLength) +{ + const std::string oldExtraData = m_fileEntryInCentralDirectory->GetExtraData(); + std::string newCDExtra; + if (!GetAlignmentNewExtra(newLength, oldExtraData, newCDExtra)) { + return false; + } + m_fileEntryInCentralDirectory->SetExtraData(newCDExtra); + m_fileEntryInCentralDirectory->SetExtraLength(newLength); + m_fileEntryInCentralDirectory->SetLength(CentralDirectory::CD_LENGTH + + m_fileEntryInCentralDirectory->GetFileNameLength() + + m_fileEntryInCentralDirectory->GetExtraLength() + + m_fileEntryInCentralDirectory->GetCommentLength()); + return true; +} + +bool ZipEntry::SetEntryHeaderNewExtraLength(uint16_t newLength) +{ + ZipEntryHeader* zipEntryHeader = m_zipEntryData->GetZipEntryHeader(); + const std::string oldExtraData = zipEntryHeader->GetExtraData(); + std::string alignmentNewExtra; + if (!GetAlignmentNewExtra(newLength, oldExtraData, alignmentNewExtra)) { + return false; + } + zipEntryHeader->SetExtraData(alignmentNewExtra); + zipEntryHeader->SetExtraLength(newLength); + zipEntryHeader->SetLength(ZipEntryHeader::HEADER_LENGTH + + zipEntryHeader->GetExtraLength() + zipEntryHeader->GetFileNameLength()); + m_zipEntryData->SetLength(zipEntryHeader->GetLength() + + m_zipEntryData->GetFileSize() + + (m_zipEntryData->GetDataDescriptor() == nullptr ? 0 : DataDescriptor::DES_LENGTH)); + return true; +} + +bool ZipEntry::GetAlignmentNewExtra(uint16_t newLength, const std::string& old, std::string& res) +{ + if (old.empty()) { + res = std::string(newLength, 0); + return true; + } + if (newLength < old.size()) { + SIGNATURE_TOOLS_LOGE("can not align %s", m_zipEntryData->GetZipEntryHeader()->GetFileName().c_str()); + return false; + } + + res = old; + res.resize(newLength); + return true; +} + +ZipEntryData* ZipEntry::GetZipEntryData() +{ + return m_zipEntryData; +} + +void ZipEntry::SetZipEntryData(ZipEntryData* zipEntryData) +{ + m_zipEntryData = zipEntryData; +} + +CentralDirectory* ZipEntry::GetCentralDirectory() +{ + return m_fileEntryInCentralDirectory; +} + +void ZipEntry::SetCentralDirectory(CentralDirectory* centralDirectory) +{ + m_fileEntryInCentralDirectory = centralDirectory; +} +} // namespace SignatureTools +} // namespace OHOS diff --git a/hapsigntool_cpp/zip/src/zip_entry_data.cpp b/hapsigntool_cpp/zip/src/zip_entry_data.cpp new file mode 100644 index 0000000000000000000000000000000000000000..46ae20ecc744e8773ca2ef0a069b06c839033976 --- /dev/null +++ b/hapsigntool_cpp/zip/src/zip_entry_data.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2024-2024 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 "file_utils.h" +#include "signature_tools_log.h" +#include "zip_entry_data.h" + +namespace OHOS { +namespace SignatureTools { +ZipEntryHeader* ZipEntryData::GetZipEntryHeader() +{ + return m_zipEntryHeader; +} + +ZipEntryData* ZipEntryData::GetZipEntry(std::ifstream& input, uint32_t entryOffset, uint32_t fileSize) +{ + uint32_t offset = entryOffset; + /* read entry header by file and offset. */ + std::string retStr; + if (FileUtils::ReadInputByOffsetAndLength(input, entryOffset, ZipEntryHeader::HEADER_LENGTH, retStr) != 0) { + SIGNATURE_TOOLS_LOGE("read zip entry head failed in file"); + return nullptr; + } + ZipEntryHeader* entryHeader = ZipEntryHeader::GetZipEntryHeader(retStr); + if (!entryHeader) { + return nullptr; + } + offset += ZipEntryHeader::HEADER_LENGTH; + + /* read entry file name and extra by offset. */ + if (!ReadEntryFileNameAndExtraByOffset(input, entryHeader, offset)) { + return nullptr; + } + /* skip file data , save file offset and size. */ + ZipEntryData* entry = new ZipEntryData(); + entry->SetFileOffset(offset); + entry->SetFileSize(fileSize); + input.seekg(fileSize, std::ios::cur); + int64_t entryLength = entryHeader->GetLength() + fileSize; + + /* set desc null flag */ + if ((entryHeader->GetFlag() & HAS_DATA_DESCRIPTOR_MASK) != NOT_HAS_DATA_DESCRIPTOR_FLAG) { + /* if entry has data descriptor, read entry data descriptor. */ + std::string retStr; + if (FileUtils::ReadInputByLength(input, DataDescriptor::DES_LENGTH, retStr) != 0) { + SIGNATURE_TOOLS_LOGE("read entry data descriptor failed in file"); + return nullptr; + } + DataDescriptor* dataDesc = DataDescriptor::GetDataDescriptor(retStr); + if (!dataDesc) { + return nullptr; + } + entryLength += DataDescriptor::DES_LENGTH; + entry->SetDataDescriptor(dataDesc); + } + entry->SetZipEntryHeader(entryHeader); + entry->SetLength(entryLength); + return entry; +} + +bool ZipEntryData::ReadEntryFileNameAndExtraByOffset(std::ifstream& input, ZipEntryHeader* entryHeader, + uint32_t& offset) +{ + if (entryHeader->GetFileNameLength() > 0) { + std::string fileNameStr; + if (FileUtils::ReadInputByLength(input, entryHeader->GetFileNameLength(), fileNameStr) != 0) { + SIGNATURE_TOOLS_LOGE("read entry file name failed in file"); + return false; + } + entryHeader->ReadFileName(fileNameStr); + offset += entryHeader->GetFileNameLength(); + } + if (entryHeader->GetExtraLength() > 0) { + std::string extraStr; + if (FileUtils::ReadInputByLength(input, entryHeader->GetExtraLength(), extraStr) != 0) { + SIGNATURE_TOOLS_LOGE("read entry file extra failed in file"); + return false; + } + entryHeader->ReadExtra(extraStr); + offset += entryHeader->GetExtraLength(); + } + return true; +} + +void ZipEntryData::SetZipEntryHeader(ZipEntryHeader* zipEntryHeader) +{ + m_zipEntryHeader = zipEntryHeader; +} + +DataDescriptor* ZipEntryData::GetDataDescriptor() +{ + return m_dataDescriptor; +} + +void ZipEntryData::SetDataDescriptor(DataDescriptor* dataDescriptor) +{ + m_dataDescriptor = dataDescriptor; +} + +uint32_t ZipEntryData::GetFileOffset() +{ + return m_fileOffset; +} + +void ZipEntryData::SetFileOffset(uint32_t fileOffset) +{ + m_fileOffset = fileOffset; +} + +uint32_t ZipEntryData::GetFileSize() +{ + return m_fileSize; +} + +void ZipEntryData::SetFileSize(uint32_t fileSize) +{ + m_fileSize = fileSize; +} + +uint32_t ZipEntryData::GetLength() +{ + return m_length; +} + +void ZipEntryData::SetLength(uint32_t length) +{ + m_length = length; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/zip/src/zip_entry_header.cpp b/hapsigntool_cpp/zip/src/zip_entry_header.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d17ebf95a32250ff59d1dd58f5f782984d9c455 --- /dev/null +++ b/hapsigntool_cpp/zip/src/zip_entry_header.cpp @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2024-2024 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 "zip_entry_header.h" +#include "signature_tools_log.h" + +namespace OHOS { +namespace SignatureTools { +ZipEntryHeader* ZipEntryHeader::GetZipEntryHeader(const std::string& bytes) +{ + ZipEntryHeader* entryHeader = new ZipEntryHeader(); + ByteBuffer bf(bytes.c_str(), bytes.size()); + + int32_t entryHeaderInt32Value; + bf.GetInt32(entryHeaderInt32Value); + if (entryHeaderInt32Value != ZipEntryHeader::SIGNATURE) { + delete entryHeader; + SIGNATURE_TOOLS_LOGE("find zip entry head failed"); + return nullptr; + } + + int16_t entryHeaderInt16Value; + bf.GetInt16(entryHeaderInt16Value); + entryHeader->SetVersion(entryHeaderInt16Value); + + bf.GetInt16(entryHeaderInt16Value); + entryHeader->SetFlag(entryHeaderInt16Value); + + bf.GetInt16(entryHeaderInt16Value); + entryHeader->SetMethod(entryHeaderInt16Value); + + bf.GetInt16(entryHeaderInt16Value); + entryHeader->SetLastTime(entryHeaderInt16Value); + + bf.GetInt16(entryHeaderInt16Value); + entryHeader->SetLastDate(entryHeaderInt16Value); + + bf.GetInt32(entryHeaderInt32Value); + entryHeader->SetCrc32(entryHeaderInt32Value); + + uint32_t entryHeaderUInt32Value; + bf.GetUInt32(entryHeaderUInt32Value); + entryHeader->SetCompressedSize(entryHeaderUInt32Value); + + bf.GetUInt32(entryHeaderUInt32Value); + entryHeader->SetUnCompressedSize(entryHeaderUInt32Value); + + uint16_t entryHeaderUInt16Value; + bf.GetUInt16(entryHeaderUInt16Value); + entryHeader->SetFileNameLength(entryHeaderUInt16Value); + + bf.GetUInt16(entryHeaderUInt16Value); + entryHeader->SetExtraLength(entryHeaderUInt16Value); + + entryHeader->SetLength(HEADER_LENGTH + entryHeader->GetFileNameLength() + entryHeader->GetExtraLength()); + + return entryHeader; +} + +void ZipEntryHeader::ReadFileName(const std::string& bytes) +{ + ByteBuffer bf(bytes.c_str(), bytes.size()); + if (m_fileNameLength > 0) { + std::string nameBytes(m_fileNameLength, 0); + bf.GetData(&nameBytes[0], m_fileNameLength); + m_fileName = nameBytes; + } +} + +void ZipEntryHeader::ReadExtra(const std::string& bytes) +{ + ByteBuffer bf(bytes.c_str(), bytes.size()); + if (m_extraLength > 0) { + std::string extra(m_extraLength, 0); + bf.GetData(&extra[0], m_extraLength); + m_extraData = extra; + } +} + +std::string ZipEntryHeader::ToBytes() +{ + ByteBuffer bf(m_length); + + bf.PutInt32(SIGNATURE); + bf.PutInt16(m_version); + bf.PutInt16(m_flag); + bf.PutInt16(m_method); + bf.PutInt16(m_lastTime); + bf.PutInt16(m_lastDate); + bf.PutInt32(m_crc32); + bf.PutUInt32(m_compressedSize); + bf.PutUInt32(m_unCompressedSize); + bf.PutUInt16(m_fileNameLength); + bf.PutUInt16(m_extraLength); + + if (m_fileNameLength > 0) { + bf.PutData(m_fileName.c_str(), m_fileName.size()); + } + if (m_extraLength > 0) { + bf.PutData(m_extraData.c_str(), m_extraData.size()); + } + + return bf.ToString(); +} + +int ZipEntryHeader::GetHeaderLength() +{ + return HEADER_LENGTH; +} + +int ZipEntryHeader::GetSIGNATURE() +{ + return SIGNATURE; +} + +short ZipEntryHeader::GetVersion() +{ + return m_version; +} + +void ZipEntryHeader::SetVersion(short version) +{ + m_version = version; +} + +short ZipEntryHeader::GetFlag() +{ + return m_flag; +} + +void ZipEntryHeader::SetFlag(short flag) +{ + m_flag = flag; +} + +short ZipEntryHeader::GetMethod() +{ + return m_method; +} + +void ZipEntryHeader::SetMethod(short method) +{ + m_method = method; +} + +short ZipEntryHeader::GetLastTime() +{ + return m_lastTime; +} + +void ZipEntryHeader::SetLastTime(short lastTime) +{ + m_lastTime = lastTime; +} + +short ZipEntryHeader::GetLastDate() +{ + return m_lastDate; +} + +void ZipEntryHeader::SetLastDate(short lastDate) +{ + m_lastDate = lastDate; +} + +int ZipEntryHeader::GetCrc32() +{ + return m_crc32; +} + +void ZipEntryHeader::SetCrc32(int crc32) +{ + m_crc32 = crc32; +} + +uint32_t ZipEntryHeader::GetCompressedSize() +{ + return m_compressedSize; +} + +void ZipEntryHeader::SetCompressedSize(uint32_t compressedSize) +{ + m_compressedSize = compressedSize; +} + +uint32_t ZipEntryHeader::GetUnCompressedSize() +{ + return m_unCompressedSize; +} + +void ZipEntryHeader::SetUnCompressedSize(uint32_t unCompressedSize) +{ + m_unCompressedSize = unCompressedSize; +} + +uint16_t ZipEntryHeader::GetFileNameLength() +{ + return m_fileNameLength; +} + +void ZipEntryHeader::SetFileNameLength(uint16_t fileNameLength) +{ + m_fileNameLength = fileNameLength; +} + +uint16_t ZipEntryHeader::GetExtraLength() +{ + return m_extraLength; +} + +void ZipEntryHeader::SetExtraLength(uint16_t extraLength) +{ + m_extraLength = extraLength; +} + +std::string ZipEntryHeader::GetFileName() const +{ + return m_fileName; +} + +void ZipEntryHeader::SetFileName(const std::string& fileName) +{ + m_fileName = fileName; +} + +std::string ZipEntryHeader::GetExtraData() const +{ + return m_extraData; +} + +void ZipEntryHeader::SetExtraData(const std::string& extraData) +{ + m_extraData = extraData; +} + +uint32_t ZipEntryHeader::GetLength() +{ + return m_length; +} + +void ZipEntryHeader::SetLength(uint32_t length) +{ + m_length = length; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/zip/src/zip_signer.cpp b/hapsigntool_cpp/zip/src/zip_signer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6524e4b0eb0583c447cf93ad86c6f8d0f68cbf86 --- /dev/null +++ b/hapsigntool_cpp/zip/src/zip_signer.cpp @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2024-2024 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 "file_utils.h" +#include "zip_entry.h" +#include "zip_signer.h" + +namespace OHOS { +namespace SignatureTools { +bool ZipSigner::Init(std::ifstream& inputFile) +{ + if (!inputFile.good()) { + return false; + } + + /* 1. get eocd data */ + m_endOfCentralDirectory = GetZipEndOfCentralDirectory(inputFile); + if (!m_endOfCentralDirectory) { + SIGNATURE_TOOLS_LOGE("get eocd data failed."); + return false; + } + + m_cDOffset = m_endOfCentralDirectory->GetOffset(); + + /* 2. use eocd's cd offset, get cd data */ + if (!GetZipCentralDirectory(inputFile)) { + SIGNATURE_TOOLS_LOGE("get zip central directory failed."); + return false; + } + + /* 3. use cd's entry offset and file size, get entry data */ + if (!GetZipEntries(inputFile)) { + SIGNATURE_TOOLS_LOGE("get zip entries failed."); + return false; + } + + ZipEntry* endEntry = m_zipEntries[m_zipEntries.size() - 1]; + CentralDirectory* endCD = endEntry->GetCentralDirectory(); + ZipEntryData* endEntryData = endEntry->GetZipEntryData(); + m_signingOffset = endCD->GetOffset() + endEntryData->GetLength(); + + /* 4. file all data - eocd - cd - entry = sign block */ + m_signingBlock = GetSigningBlock(inputFile); + + return true; +} + +EndOfCentralDirectory* ZipSigner::GetZipEndOfCentralDirectory(std::ifstream& input) +{ + /* move file pointer to the end */ + input.seekg(0, std::ios::end); + uint64_t fileSize = static_cast(input.tellg()); + /* move file pointer to the begin */ + input.seekg(0, std::ios::beg); + + if (fileSize < EndOfCentralDirectory::EOCD_LENGTH) { + SIGNATURE_TOOLS_LOGE("find zip eocd failed"); + return nullptr; + } + + /* try to read EOCD without comment */ + int eocdLength = EndOfCentralDirectory::EOCD_LENGTH; + m_eOCDOffset = fileSize - eocdLength; + + std::string retStr; + int ret = FileUtils::ReadFileByOffsetAndLength(input, m_eOCDOffset, eocdLength, retStr); + if (0 != ret) { + SIGNATURE_TOOLS_LOGE("read eocd without comment failed in file"); + return nullptr; + } + + std::optional eocdByBytes = EndOfCentralDirectory::GetEOCDByBytes(retStr); + if (eocdByBytes) { + return eocdByBytes.value(); + } + + /* try to search EOCD with comment */ + uint64_t eocdMaxLength = std::min(static_cast(EndOfCentralDirectory::EOCD_LENGTH + MAX_COMMENT_LENGTH), + fileSize); + m_eOCDOffset = static_cast(input.tellg()) - eocdMaxLength; + + retStr.clear(); + ret = FileUtils::ReadFileByOffsetAndLength(input, m_eOCDOffset, eocdMaxLength, retStr); + if (0 != ret) { + SIGNATURE_TOOLS_LOGE("read eocd with comment failed in file"); + return nullptr; + } + + for (int start = 0; start < eocdMaxLength; start++) { + eocdByBytes = EndOfCentralDirectory::GetEOCDByBytes(retStr, start); + if (eocdByBytes) { + m_eOCDOffset += start; + return eocdByBytes.value(); + } + } + SIGNATURE_TOOLS_LOGE("read zip failed: can not find eocd in file"); + PrintErrorNumberMsg("ZIP_ERROR", ZIP_ERROR, "can not find eocd in file"); + return nullptr; +} + +bool ZipSigner::GetZipCentralDirectory(std::ifstream& input) +{ + input.seekg(0, std::ios::beg); + + uint16_t cDtotal = m_endOfCentralDirectory->GetcDTotal(); + m_zipEntries.reserve(cDtotal); + /* read full central directory bytes */ + std::string retStr; + + int ret = FileUtils::ReadFileByOffsetAndLength(input, m_cDOffset, m_endOfCentralDirectory->GetcDSize(), retStr); + if (0 != ret) { + SIGNATURE_TOOLS_LOGE("read full central directory failed in file"); + return false; + } + + if (retStr.size() < CentralDirectory::CD_LENGTH) { + SIGNATURE_TOOLS_LOGE("find zip cd failed"); + return false; + } + + ByteBuffer bf(retStr.c_str(), retStr.size()); + + int offset = 0; + /* one by one format central directory */ + while (offset < retStr.size()) { + CentralDirectory* cd = new CentralDirectory(); + if (!CentralDirectory::GetCentralDirectory(bf, cd)) { + return false; + } + ZipEntry* entry = new ZipEntry(); + entry->SetCentralDirectory(cd); + m_zipEntries.emplace_back(entry); + offset += cd->GetLength(); + } + + if (offset + m_cDOffset != m_eOCDOffset) { + SIGNATURE_TOOLS_LOGE("cd end offset not equals to eocd offset, maybe this is a zip64 file"); + return false; + } + return true; +} + +std::string ZipSigner::GetSigningBlock(std::ifstream& file) +{ + uint64_t size = m_cDOffset - m_signingOffset; + if (size < 0) { + SIGNATURE_TOOLS_LOGE("signing offset in front of entry end"); + return ""; + } + if (size == 0) { + return ""; + } + + std::string retStr; + int ret = FileUtils::ReadFileByOffsetAndLength(file, m_signingOffset, size, retStr); + if (0 != ret) { + SIGNATURE_TOOLS_LOGE("read signing block failed in file"); + return ""; + } + return retStr; +} + +bool ZipSigner::GetZipEntries(std::ifstream& input) +{ + /* use central directory data, find entry data */ + for (auto& entry : m_zipEntries) { + CentralDirectory* cd = entry->GetCentralDirectory(); + uint32_t offset = cd->GetOffset(); + uint32_t unCompressedSize = cd->GetUnCompressedSize(); + uint32_t compressedSize = cd->GetCompressedSize(); + uint32_t fileSize = cd->GetMethod() == FILE_UNCOMPRESS_METHOD_FLAG ? unCompressedSize : compressedSize; + + ZipEntryData* zipEntryData = ZipEntryData::GetZipEntry(input, offset, fileSize); + if (!zipEntryData) { + return false; + } + if (m_cDOffset - offset < zipEntryData->GetLength()) { + SIGNATURE_TOOLS_LOGE("cd offset in front of entry end"); + return false; + } + entry->SetZipEntryData(zipEntryData); + } + return true; +} + +bool ZipSigner::ToFile(std::ifstream& input, std::ofstream& output) +{ + SIGNATURE_TOOLS_LOGI("Zip To File begin"); + if (!input.good()) { + SIGNATURE_TOOLS_LOGE("read zip input file failed"); + return false; + } + if (!output.good()) { + SIGNATURE_TOOLS_LOGE("read zip output file failed"); + return false; + } + + for (const auto& entry : m_zipEntries) { + ZipEntryData* zipEntryData = entry->GetZipEntryData(); + std::string zipEntryHeaderStr = zipEntryData->GetZipEntryHeader()->ToBytes(); + if (!FileUtils::WriteByteToOutFile(zipEntryHeaderStr, output)) { + return false; + } + + uint32_t fileOffset = zipEntryData->GetFileOffset(); + uint32_t fileSize = zipEntryData->GetFileSize(); + bool isSuccess = FileUtils::AppendWriteFileByOffsetToFile(input, output, fileOffset, fileSize); + if (!isSuccess) { + SIGNATURE_TOOLS_LOGE("write zip data failed"); + return false; + } + DataDescriptor* dataDescriptor = zipEntryData->GetDataDescriptor(); + if (dataDescriptor) { + std::string dataDescriptorStr = dataDescriptor->ToBytes(); + if (!FileUtils::WriteByteToOutFile(dataDescriptorStr, output)) { + return false; + } + } + } + + if (!m_signingBlock.empty()) { + if (!FileUtils::WriteByteToOutFile(m_signingBlock, output)) { + return false; + } + } + + for (const auto& entry : m_zipEntries) { + CentralDirectory* cd = entry->GetCentralDirectory(); + if (!FileUtils::WriteByteToOutFile(cd->ToBytes(), output)) { + return false; + } + } + + if (!FileUtils::WriteByteToOutFile(m_endOfCentralDirectory->ToBytes(), output)) { + return false; + } + + SIGNATURE_TOOLS_LOGI("Zip To File end"); + return true; +} + +void ZipSigner::Alignment(int alignment) +{ + Sort(); + bool isFirstUnRunnableFile = true; + for (const auto& entry : m_zipEntries) { + ZipEntryData* zipEntryData = entry->GetZipEntryData(); + short method = zipEntryData->GetZipEntryHeader()->GetMethod(); + if (method != FILE_UNCOMPRESS_METHOD_FLAG && !isFirstUnRunnableFile) { + /* only align uncompressed entry and the first compress entry. */ + break; + } + int alignBytes; + if (method == FILE_UNCOMPRESS_METHOD_FLAG && + FileUtils::IsRunnableFile(zipEntryData->GetZipEntryHeader()->GetFileName())) { + /* .abc and .so file align 4096 byte. */ + alignBytes = 4096; + } else if (isFirstUnRunnableFile) { + /* the first file after runnable file, align 4096 byte. */ + alignBytes = 4096; + isFirstUnRunnableFile = false; + } else { + /* normal file align 4 byte. */ + alignBytes = alignment; + } + int add = entry->Alignment(alignBytes); + if (add > 0) { + ResetOffset(); + } + } +} + +void ZipSigner::RemoveSignBlock() +{ + m_signingBlock = std::string(); + ResetOffset(); +} + +void ZipSigner::Sort() +{ + /* sort uncompress file (so, abc, an) - other uncompress file - compress file */ + std::sort(m_zipEntries.begin(), m_zipEntries.end(), [&](ZipEntry* entry1, ZipEntry* entry2) { + short entry1Method = entry1->GetZipEntryData()->GetZipEntryHeader()->GetMethod(); + short entry2Method = entry2->GetZipEntryData()->GetZipEntryHeader()->GetMethod(); + std::string entry1FileName = entry1->GetZipEntryData()->GetZipEntryHeader()->GetFileName(); + std::string entry2FileName = entry2->GetZipEntryData()->GetZipEntryHeader()->GetFileName(); + if (entry1Method == FILE_UNCOMPRESS_METHOD_FLAG && entry2Method == FILE_UNCOMPRESS_METHOD_FLAG) { + bool isRunnableFile1 = FileUtils::IsRunnableFile(entry1FileName); + bool isRunnableFile2 = FileUtils::IsRunnableFile(entry2FileName); + if (isRunnableFile1 && isRunnableFile2) { + return entry1FileName < entry2FileName; + } else if (isRunnableFile1) { + return true; + } else if (isRunnableFile2) { + return false; + } + } else if (entry1Method == FILE_UNCOMPRESS_METHOD_FLAG) { + return true; + } else if (entry2Method == FILE_UNCOMPRESS_METHOD_FLAG) { + return false; + } + return entry1FileName < entry2FileName; + }); + ResetOffset(); +} + +void ZipSigner::ResetOffset() +{ + uint32_t offset = 0U; + uint32_t cdLength = 0U; + for (const auto& entry : m_zipEntries) { + entry->GetCentralDirectory()->SetOffset(offset); + offset += entry->GetZipEntryData()->GetLength(); + cdLength += entry->GetCentralDirectory()->GetLength(); + } + if (!m_signingBlock.empty()) { + offset += m_signingBlock.size(); + } + m_cDOffset = offset; + m_endOfCentralDirectory->SetOffset(offset); + m_endOfCentralDirectory->SetcDSize(cdLength); + offset += cdLength; + m_eOCDOffset = offset; +} + +std::vector& ZipSigner::GetZipEntries() +{ + return m_zipEntries; +} + +void ZipSigner::SetZipEntries(const std::vector& zipEntries) +{ + m_zipEntries = zipEntries; +} + +uint32_t ZipSigner::GetSigningOffset() +{ + return m_signingOffset; +} + +void ZipSigner::SetSigningOffset(uint32_t signingOffset) +{ + m_signingOffset = signingOffset; +} + +std::string ZipSigner::GetSigningBlock() +{ + return m_signingBlock; +} + +void ZipSigner::SetSigningBlock(const std::string& signingBlock) +{ + m_signingBlock = signingBlock; +} + +uint32_t ZipSigner::GetCDOffset() +{ + return m_cDOffset; +} + +void ZipSigner::SetCDOffset(uint32_t cDOffset) +{ + m_cDOffset = cDOffset; +} + +uint32_t ZipSigner::GetEOCDOffset() +{ + return m_eOCDOffset; +} + +void ZipSigner::SetEOCDOffset(uint32_t eOCDOffset) +{ + m_eOCDOffset = eOCDOffset; +} + +EndOfCentralDirectory* ZipSigner::GetEndOfCentralDirectory() +{ + return m_endOfCentralDirectory; +} + +void ZipSigner::SetEndOfCentralDirectory(EndOfCentralDirectory* endOfCentralDirectory) +{ + m_endOfCentralDirectory = endOfCentralDirectory; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file diff --git a/hapsigntool_cpp/zip/src/zip_utils.cpp b/hapsigntool_cpp/zip/src/zip_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b5c9839267c8550648c2b2eab49101a9dea308a6 --- /dev/null +++ b/hapsigntool_cpp/zip/src/zip_utils.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024-2024 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 "zip_utils.h" + +namespace OHOS { +namespace SignatureTools { +bool ZipUtils::SetCentralDirectoryOffset(ByteBuffer& eocd, int64_t offset) +{ + if (!SetUInt32ToBuffer(eocd, eocd.GetPosition() + ZIP_CENTRAL_DIR_OFFSET_IN_EOCD, offset)) { + SIGNATURE_TOOLS_LOGE("Set Central Directory Offset failed."); + return false; + } + return true; +} + +bool ZipUtils::SetUInt32ToBuffer(ByteBuffer& buffer, int offset, int64_t value) +{ + SIGNATURE_TOOLS_LOGI("offset: %d, value: %" PRId64 ", UINT32_MAX_VALUE: %" PRId64, + offset, value, UINT32_MAX_VALUE); + if ((value < 0) || (value > UINT32_MAX_VALUE)) { + SIGNATURE_TOOLS_LOGE("invalid_argument. value of out range: %" PRId64, value); + return false; + } + buffer.PutInt32(offset, static_cast(value)); + return true; +} +} // namespace SignatureTools +} // namespace OHOS \ No newline at end of file