diff --git a/README.md b/README.md index 04a052a4c0aa121b15ced6b456cc391123347bc7..5eec1de6938308ab2c440767cc4f0fba63b34875 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ The parameters in the command are described as follows: ```shell -java -jar hap-sign-tool.jar sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "result\app1.pem" -profileFile "result\app1-profile.p7b" -inFile "app1-unsigned.zip" -keystoreFile "result\ohtest.jks" -outFile "result\app1-unsigned.hap" -keyPwd "123456" -keystorePwd "123456" +java -jar hap-sign-tool.jar sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "result\app1.pem" -profileFile "result\app1-profile.p7b" -inFile "app1-unsigned.zip" -keystoreFile "result\ohtest.jks" -outFile "result\app1-unsigned.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1" ``` The parameters in the command are described as follows: @@ -97,12 +97,13 @@ The parameters in the command are described as follows: ├── -appCertFile # Application signing certificate (certificate chain, in the end-entity certificate, intermediate CA certificate, and root certificate order). It is mandatory. ├── -profileFile # Singed provisioning profile, in p7b format. It is mandatory. ├── -profileSigned # Whether the profile is signed. The value 1 means signed, and value 0 means unsigned. The default value is 1. It is optional. - ├── -inForm # Raw file, in .zip (default) or .bin format. It is optional. + ├── -inForm # Raw file, in .zip (default) or .bin or .elf format. It is optional. ├── -inFile # Raw application package, in .zip or .bin format. It is mandatory. ├── -signAlg # Signature algorithm, which can be SHA256withECDSA or SHA384withECDSA. It is mandatory. ├── -keystoreFile # KeyStore (KS) file, in JKS or P12 format. It is mandatory if the signing mode is localSign. ├── -keystorePwd # KS password. It is optional. ├── -outFile # Signed HAP file to generate. It is mandatory. + ├── -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. 2. One-click signature @@ -276,6 +277,7 @@ Procedure: ├── -keystoreFile # KS file, in JKS or P12 format. It is mandatory if the signing mode is localSign. ├── -keystorePwd # KS password. It is optional. ├── -outFile # Signed HAP file to generate. It is mandatory. + ├── -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. 10.Verify the HAP Signature. diff --git a/README_ZH.md b/README_ZH.md index 5ce50a28953648bd0b855f8d0e1ac0edc18d3149..eeee669ffae3a20b0a7c45bd4d27fccacda39da5 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -96,7 +96,7 @@ java -jar hap-sign-tool.jar sign-profile -keyAlias "oh-profile1-key-v1" -signAl ```shell -java -jar hap-sign-tool.jar sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "result\app1.pem" -profileFile "result\app1-profile.p7b" -inFile "app1-unsigned.zip" -keystoreFile "result\ohtest.jks" -outFile "result\app1-unsigned.hap" -keyPwd "123456" -keystorePwd "123456" +java -jar hap-sign-tool.jar sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "result\app1.pem" -profileFile "result\app1-profile.p7b" -inFile "app1-unsigned.zip" -keystoreFile "result\ohtest.jks" -outFile "result\app1-unsigned.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1" ``` 该命令的参数说明如下: @@ -113,7 +113,8 @@ java -jar hap-sign-tool.jar sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256 ├── -keystoreFile #密钥库文件,localSign模式时为必填项,JKS或P12格式 ├── -keystorePwd #密钥库口令,可选项 ├── -outFile #输出签名后的包文件,必填项 - + ├── -signcode #指示包文件是否带有代码签名,1表示有代码签名,0表示没有代码签名,默认1。可选项 + 2.一键签名 @@ -286,6 +287,7 @@ java -jar hap-sign-tool.jar sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256 ├── -keystoreFile # 密钥库文件,localSign模式时为必填项,JKS或P12格式 ├── -keystorePwd # 密钥库口令,可选项 ├── -outFile # 输出签名后的包文件,必填项 + ├── -signcode # 指示包文件是否带有代码签名,1表示有代码签名,0表示没有代码签名,默认1。可选项 10.hap应用包文件验签 diff --git a/hapsigntool/hap_sign_tool/src/main/java/com/ohos/hapsigntool/HapSignTool.java b/hapsigntool/hap_sign_tool/src/main/java/com/ohos/hapsigntool/HapSignTool.java index ab4c6cdb35d93af34fbf47ac63adc34b95d44905..3d23079464ece5aa9bcb9a9b163e81a030ea3d5d 100644 --- a/hapsigntool/hap_sign_tool/src/main/java/com/ohos/hapsigntool/HapSignTool.java +++ b/hapsigntool/hap_sign_tool/src/main/java/com/ohos/hapsigntool/HapSignTool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -15,7 +15,6 @@ package com.ohos.hapsigntool; - import com.ohos.hapsigntool.api.ServiceApi; import com.ohos.hapsigntool.api.SignToolServiceImpl; import com.ohos.hapsigntool.api.model.Options; @@ -27,9 +26,13 @@ import com.ohos.hapsigntoolcmd.CmdUtil; import com.ohos.hapsigntoolcmd.CmdUtil.Method; import com.ohos.hapsigntoolcmd.HelpDocument; import com.ohos.hapsigntoolcmd.Params; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.util.ArrayList; +import java.util.List; + /** * HapSignTool. * @@ -66,6 +69,12 @@ public final class HapSignTool { */ private static final String NOT_SIGNED = "0"; + private static List informList = new ArrayList(){{ + add("bin"); + add("elf"); + add("zip"); + }}; + private HapSignTool() { } @@ -76,8 +85,8 @@ public final class HapSignTool { */ public static void main(String[] args) { try { - boolean result = processCmd(args); - if (!result) { + boolean isSuccess = processCmd(args); + if (!isSuccess) { System.exit(1); } } catch (CustomException exception) { @@ -106,67 +115,65 @@ public final class HapSignTool { Params params = CmdUtil.convert2Params(args); LOGGER.debug(params.toString()); LOGGER.info("Start {}", params.getMethod()); - boolean result; - result = dispatchParams(params, api); - if (result) { + boolean isSuccess = dispatchParams(params, api); + if (isSuccess) { LOGGER.info(String.format("%s %s", params.getMethod(), "success")); } else { LOGGER.info(String.format("%s %s", params.getMethod(), "failed")); } - return result; + return isSuccess; } return true; } private static boolean callGenerators(Params params, ServiceApi api) { - boolean result = false; + boolean isSuccess = false; switch (params.getMethod()) { case Method.GENERATE_APP_CERT: - result = runAppCert(params.getOptions(), api); + isSuccess = runAppCert(params.getOptions(), api); break; case Method.GENERATE_CA: - result = runCa(params.getOptions(), api); + isSuccess = runCa(params.getOptions(), api); break; case Method.GENERATE_CERT: - result = runCert(params.getOptions(), api); + isSuccess = runCert(params.getOptions(), api); break; case Method.GENERATE_CSR: - result = runCsr(params.getOptions(), api); + isSuccess = runCsr(params.getOptions(), api); break; case Method.GENERATE_KEYPAIR: - result = runKeypair(params.getOptions(), api); + isSuccess = runKeypair(params.getOptions(), api); break; case Method.GENERATE_PROFILE_CERT: - result = runProfileCert(params.getOptions(), api); + isSuccess = runProfileCert(params.getOptions(), api); break; default: CustomException.throwException(ERROR.COMMAND_ERROR, "Unsupported cmd"); break; } - return result; + return isSuccess; } private static boolean dispatchParams(Params params, ServiceApi api) { - boolean result; + boolean isSuccess; switch (params.getMethod()) { case Method.SIGN_APP: - result = runSignApp(params.getOptions(), api); + isSuccess = runSignApp(params.getOptions(), api); break; case Method.SIGN_PROFILE: - result = runSignProfile(params.getOptions(), api); + isSuccess = runSignProfile(params.getOptions(), api); break; case Method.VERIFY_APP: - result = runVerifyApp(params.getOptions(), api); + isSuccess = runVerifyApp(params.getOptions(), api); break; case Method.VERIFY_PROFILE: - result = runVerifyProfile(params.getOptions(), api); + isSuccess = runVerifyProfile(params.getOptions(), api); break; default: - result = callGenerators(params, api); + isSuccess = callGenerators(params, api); break; } - - return result; + return isSuccess; } private static void checkEndCertArguments(Options params) { @@ -186,7 +193,7 @@ public final class HapSignTool { String keyStoreFile = params.getString(Options.KEY_STORE_FILE); FileUtils.validFileType(keyStoreFile, "p12", "jks"); - if (params.containsKey(Options.ISSUER_KEY_STORE_FILE)){ + if (params.containsKey(Options.ISSUER_KEY_STORE_FILE)) { String issuerKeyStoreFile = params.getString(Options.ISSUER_KEY_STORE_FILE); FileUtils.validFileType(issuerKeyStoreFile, "p12", "jks"); } @@ -226,7 +233,7 @@ public final class HapSignTool { String signAlg = params.getString(Options.SIGN_ALG); CmdUtil.judgeSignAlgType(signAlg); FileUtils.validFileType(params.getString(Options.KEY_STORE_FILE), "p12", "jks"); - if (params.containsKey(Options.ISSUER_KEY_STORE_FILE)){ + if (params.containsKey(Options.ISSUER_KEY_STORE_FILE)) { String issuerKeyStoreFile = params.getString(Options.ISSUER_KEY_STORE_FILE); FileUtils.validFileType(issuerKeyStoreFile, "p12", "jks"); } @@ -263,7 +270,7 @@ public final class HapSignTool { } private static boolean runSignApp(Options params, ServiceApi api) { - params.required(Options.MODE, Options.IN_FILE, Options.OUT_FILE, Options.PROFILE_FILE, Options.SIGN_ALG); + params.required(Options.MODE, Options.IN_FILE, Options.OUT_FILE, Options.SIGN_ALG); String mode = params.getString(Options.MODE); if (!LOCAL_SIGN.equalsIgnoreCase(mode) && !REMOTE_SIGN.equalsIgnoreCase(mode) @@ -277,7 +284,7 @@ public final class HapSignTool { } checkProfile(params); String inForm = params.getString(Options.IN_FORM); - if (!StringUtils.isEmpty(inForm) && !"zip".equalsIgnoreCase(inForm) && !"bin".equalsIgnoreCase(inForm)) { + if (!StringUtils.isEmpty(inForm) && !informList.contains(inForm)) { CustomException.throwException(ERROR.NOT_SUPPORT_ERROR, "inForm params is incorrect"); } String signAlg = params.getString(Options.SIGN_ALG); @@ -287,8 +294,13 @@ public final class HapSignTool { } private static void checkProfile(Options params) { + String inForm = params.getString(Options.IN_FORM); String profileFile = params.getString(Options.PROFILE_FILE); - String profileSigned = params.getString(Options.PROFILE_SIGNED,SIGNED); + String profileSigned = params.getString(Options.PROFILE_SIGNED, SIGNED); + + if ("elf".equalsIgnoreCase(inForm) && StringUtils.isEmpty(profileFile)) { + return; + } if (!SIGNED.equals(profileSigned) && !NOT_SIGNED.equals(profileSigned)) { CustomException.throwException(ERROR.NOT_SUPPORT_ERROR, "profileSigned params is incorrect"); } @@ -321,7 +333,7 @@ public final class HapSignTool { private static boolean runVerifyApp(Options params, ServiceApi api) { params.required(Options.IN_FILE, Options.OUT_CERT_CHAIN, Options.OUT_PROFILE); - FileUtils.validFileType(params.getString(Options.IN_FILE), "hap", "bin"); + FileUtils.validFileType(params.getString(Options.IN_FILE), "hap"); FileUtils.validFileType(params.getString(Options.OUT_CERT_CHAIN), "cer"); FileUtils.validFileType(params.getString(Options.OUT_PROFILE), "p7b"); return api.verifyHap(params); diff --git a/hapsigntool/hap_sign_tool/src/main/resources/help.txt b/hapsigntool/hap_sign_tool/src/main/resources/help.txt index 4f293806a83eb915ac8de69a36c3b109391a92ec..b1909942472633d1bbe0b0fadfd0c12f9700cd7e 100644 --- a/hapsigntool/hap_sign_tool/src/main/resources/help.txt +++ b/hapsigntool/hap_sign_tool/src/main/resources/help.txt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -183,9 +183,10 @@ USAGE: [options] -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 "D:\OH\app-release-cert.cer" -profileFile "D:\OH\signed-profile.p7b" -inFile "D:\OH\app1-unsigned.hap" -signAlg SHA256withECDSA -keystoreFile "D:\OH\app-keypair.jks" -keystorePwd ****** -outFile "D:\OH\app1-signed.hap -compatibleVersion 8" + sign-app -mode localSign -keyAlias "oh-app1-key-v1" -appCertFile "D:\OH\app-release-cert.cer" -profileFile "D:\OH\signed-profile.p7b" -inFile "D:\OH\app1-unsigned.hap" -signAlg SHA256withECDSA -keystoreFile "D:\OH\app-keypair.jks" -keystorePwd ****** -outFile "D:\OH\app1-signed.hap -compatibleVersion 8" -signcode "1" verify-app [options]: -inFile : signed application package file, hap or bin format, required fields; diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/api/SignToolServiceImpl.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/api/SignToolServiceImpl.java index ff79b211a39cc5c3418060ef2de062d0e799a9c7..d97dc144dbc7cab2185e43a8565bfd84db7a1d8e 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/api/SignToolServiceImpl.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/api/SignToolServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -15,7 +15,6 @@ package com.ohos.hapsigntool.api; - import com.ohos.hapsigntool.api.model.Options; import com.ohos.hapsigntool.cert.CertTools; import com.ohos.hapsigntool.error.CustomException; @@ -32,6 +31,7 @@ import com.ohos.hapsigntool.utils.CertUtils; import com.ohos.hapsigntool.utils.FileUtils; import com.ohos.hapsigntool.utils.ProfileUtils; import com.ohos.hapsigntool.utils.StringUtils; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.bouncycastle.jce.provider.BouncyCastleProvider; @@ -44,10 +44,8 @@ import java.security.Security; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import java.util.Arrays; +import java.util.List; /** * Main entry of lib. @@ -55,10 +53,6 @@ import java.util.Arrays; * @since 2021/12/28 */ public class SignToolServiceImpl implements ServiceApi { - static { - Security.addProvider(new BouncyCastleProvider()); - } - /** * App signing Capabilty Bytes. */ @@ -74,6 +68,10 @@ public class SignToolServiceImpl implements ServiceApi { */ private static final Logger logger = LogManager.getLogger(ServiceApi.class); + static { + Security.addProvider(new BouncyCastleProvider()); + } + /** * Generate keyStore. * @@ -123,7 +121,7 @@ public class SignToolServiceImpl implements ServiceApi { adapter.errorIfNotExist(issuerAlias); KeyPair subjectKeyPair = adapter.getAliasKey(false); - if (options.containsKey(Options.ISSUER_KEY_STORE_FILE)){ + if (options.containsKey(Options.ISSUER_KEY_STORE_FILE)) { adapter.setKeyStoreHelper(null); adapter.setIssuerKeyStoreFile(true); } @@ -144,28 +142,28 @@ public class SignToolServiceImpl implements ServiceApi { @Override public boolean generateCA(Options options) { LocalizationAdapter adapter = new LocalizationAdapter(options); - boolean genRootCA = StringUtils.isEmpty(options.getString(Options.ISSUER_KEY_ALIAS)); + boolean isEmpty = StringUtils.isEmpty(options.getString(Options.ISSUER_KEY_ALIAS)); KeyPair subKey = adapter.getAliasKey(true); KeyPair rootKey; String ksFile = options.getString(Options.KEY_STORE_FILE); String iksFile = options.getString(Options.ISSUER_KEY_STORE_FILE); - if (genRootCA) { - if (!StringUtils.isEmpty(iksFile) && !ksFile.equals(iksFile)){ + if (isEmpty) { + if (!StringUtils.isEmpty(iksFile) && !ksFile.equals(iksFile)) { CustomException.throwException(ERROR.WRITE_FILE_ERROR, - String.format("Parameter '%s' and parameter '%s' are inconsistent",ksFile,iksFile)); + String.format("Parameter '%s' and parameter '%s' are inconsistent", ksFile, iksFile)); } - if (options.containsKey(Options.ISSUER_KEY_STORE_RIGHTS) ){ + if (options.containsKey(Options.ISSUER_KEY_STORE_RIGHTS)) { boolean isEqual = Arrays.equals(options.getChars(Options.KEY_STORE_RIGHTS), options.getChars(Options.ISSUER_KEY_STORE_RIGHTS)); - if (!isEqual){ + if (!isEqual) { CustomException.throwException(ERROR.WRITE_FILE_ERROR, String.format("Parameter '%s' and parameter '%s' are inconsistent", - Options.KEY_STORE_RIGHTS,Options.ISSUER_KEY_STORE_RIGHTS)); + Options.KEY_STORE_RIGHTS, Options.ISSUER_KEY_STORE_RIGHTS)); } } rootKey = subKey; } else { - if (options.containsKey(Options.ISSUER_KEY_STORE_FILE)){ + if (options.containsKey(Options.ISSUER_KEY_STORE_FILE)) { FileUtils.validFileType(options.getString(Options.ISSUER_KEY_STORE_FILE), "p12", "jks"); adapter.setKeyStoreHelper(null); adapter.setIssuerKeyStoreFile(true); @@ -176,7 +174,7 @@ public class SignToolServiceImpl implements ServiceApi { byte[] csr = CertTools.generateCsr(subKey, adapter.getSignAlg(), adapter.getSubject()); X509Certificate cert; - if (genRootCA) { + if (isEmpty) { cert = CertTools.generateRootCaCert(rootKey, csr, adapter); } else { cert = CertTools.generateSubCert(rootKey, csr, adapter); @@ -194,7 +192,7 @@ public class SignToolServiceImpl implements ServiceApi { public boolean generateAppCert(Options options) { LocalizationAdapter adapter = new LocalizationAdapter(options); KeyPair keyPair = adapter.getAliasKey(false); - if (options.containsKey(Options.ISSUER_KEY_STORE_FILE)){ + if (options.containsKey(Options.ISSUER_KEY_STORE_FILE)) { adapter.setKeyStoreHelper(null); adapter.setIssuerKeyStoreFile(true); } @@ -203,15 +201,7 @@ public class SignToolServiceImpl implements ServiceApi { byte[] csr = CertTools.generateCsr(keyPair, adapter.getSignAlg(), adapter.getSubject()); X509Certificate cert = CertTools.generateEndCert(issueKeyPair, csr, adapter, APP_SIGNING_CAPABILITY); - if (adapter.isOutFormChain()) { - List certificates = new ArrayList<>(); - certificates.add(cert); - certificates.add(adapter.getSubCaCertFile()); - certificates.add(adapter.getCaCertFile()); - return outputCertChain(certificates, adapter.getOutFile()); - } else { - return outputCert(cert, adapter.getOutFile()); - } + return getOutputCert(adapter, cert); } /** @@ -224,7 +214,7 @@ public class SignToolServiceImpl implements ServiceApi { public boolean generateProfileCert(Options options) { LocalizationAdapter adapter = new LocalizationAdapter(options); KeyPair keyPair = adapter.getAliasKey(false); - if (options.containsKey(Options.ISSUER_KEY_STORE_FILE)){ + if (options.containsKey(Options.ISSUER_KEY_STORE_FILE)) { adapter.setKeyStoreHelper(null); adapter.setIssuerKeyStoreFile(true); } @@ -233,6 +223,10 @@ public class SignToolServiceImpl implements ServiceApi { byte[] csr = CertTools.generateCsr(keyPair, adapter.getSignAlg(), adapter.getSubject()); X509Certificate cert = CertTools.generateEndCert(issueKeyPair, csr, adapter, PROFILE_SIGNING_CAPABILITY); + return getOutputCert(adapter, cert); + } + + private boolean getOutputCert(LocalizationAdapter adapter, X509Certificate cert) { if (adapter.isOutFormChain()) { List certificates = new ArrayList<>(); certificates.add(cert); @@ -252,19 +246,19 @@ public class SignToolServiceImpl implements ServiceApi { */ @Override public boolean signProfile(Options options) { - boolean result; + boolean isSuccess; try { LocalizationAdapter adapter = new LocalizationAdapter(options); byte[] provisionContent = ProfileUtils.getProvisionContent(new File(adapter.getInFile())); byte[] p7b = ProfileSignTool.generateP7b(adapter, provisionContent); FileUtils.write(p7b, new File(adapter.getOutFile())); - result = true; + isSuccess = true; } catch (IOException exception) { logger.debug(exception.getMessage(), exception); logger.error(exception.getMessage()); - result = false; + isSuccess = false; } - return result; + return isSuccess; } /** @@ -275,27 +269,26 @@ public class SignToolServiceImpl implements ServiceApi { */ @Override public boolean verifyProfile(Options options) { - boolean result; + boolean isSign; try { LocalizationAdapter adapter = new LocalizationAdapter(options); VerifyHelper verifyHelper = new VerifyHelper(); byte[] p7b = FileUtils.readFile(new File(adapter.getInFile())); VerificationResult verificationResult = verifyHelper.verify(p7b); - result = verificationResult.isVerifiedPassed(); - if (!result) { + isSign = verificationResult.isVerifiedPassed(); + if (!isSign) { logger.error(verificationResult.getMessage()); } outputString(FileUtils.GSON_PRETTY_PRINT.toJson(verificationResult), adapter.getOutFile()); } catch (IOException exception) { logger.debug(exception.getMessage(), exception); logger.error(exception.getMessage()); - result = false; + isSign = false; } catch (VerifyException e) { CustomException.throwException(ERROR.VERIFY_ERROR, "Verify Profile Failed! " + e.getMessage()); - result = false; - + isSign = false; } - return result; + return isSign; } /** @@ -311,7 +304,7 @@ public class SignToolServiceImpl implements ServiceApi { SignProvider signProvider; if ("localSign".equalsIgnoreCase(mode)) { signProvider = new LocalJKSSignProvider(); - } else if ("remoteSign".equalsIgnoreCase(mode)){ + } else if ("remoteSign".equalsIgnoreCase(mode)) { signProvider = new RemoteSignProvider(); } else { logger.info("Resign mode. But not implement yet"); @@ -322,6 +315,8 @@ public class SignToolServiceImpl implements ServiceApi { String inForm = options.getString(Options.IN_FORM, "zip"); if ("zip".equalsIgnoreCase(inForm)) { return signProvider.sign(options); + } else if ("elf".equalsIgnoreCase(inForm)) { + return signProvider.signElf(options); } else { return signProvider.signBin(options); } diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/entity/HwBlockHead.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/entity/HwBlockHead.java index ba283115a5b10dda774221383ee316b0730d446b..8a270554b812a10e7d5501885db894a6333bd0e1 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/entity/HwBlockHead.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/entity/HwBlockHead.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -15,11 +15,18 @@ package com.ohos.hapsigntool.hap.entity; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + /** * define class of hap signature sub-block head + * + * @since 2023/11/07 */ public class HwBlockHead { - private static final int BLOCK_LEN = 8; // current block length + private static final int BLOCK_LEN = 8; // bin block length is 8 byte + + private static final int ELF_BLOCK_LEN = 12; // elf block length is 12 byte private static final int BIT_SIZE = 8; @@ -27,15 +34,26 @@ public class HwBlockHead { private static final int TRIPLE_BIT_SIZE = 24; + /** + * get bin block length + * + * @return return bin block length + */ public static int getBlockLen() { return BLOCK_LEN; } - private HwBlockHead() { + /** + * get elf block length + * + * @return return elf block length + */ + public static int getElfBlockLen() { + return ELF_BLOCK_LEN; } /** - * get serialization of HwBlockHead + * get serialization of file type bin BlockHead * * @param type type of signature block * @param tag tags of signature block @@ -55,4 +73,22 @@ public class HwBlockHead { (byte) (offset & 0xff) }; } + + /** + * get serialization of file type elf BlockHead + * + * @param type type of signature block + * @param tag tags of signature block + * @param length the length of block data + * @param offset Byte offset of the data block relative to the start position of the signature block + * @return Byte array after serialization of HwBlockHead + */ + public static byte[] getBlockHeadLittleEndian(char type, char tag, int length, int offset) { + ByteBuffer bf = ByteBuffer.allocate(HwBlockHead.ELF_BLOCK_LEN).order(ByteOrder.LITTLE_ENDIAN); + bf.putChar(type); + bf.putChar(tag); + bf.putInt(length); + bf.putInt(offset); + return bf.array(); + } } \ No newline at end of file diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/entity/HwSignHead.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/entity/HwSignHead.java index 6584253be06e08e60d4453b73e2680644787b073..0010344c927ed9dbf85d413939d0629074dce365 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/entity/HwSignHead.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/entity/HwSignHead.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -18,6 +18,8 @@ package com.ohos.hapsigntool.hap.entity; import com.ohos.hapsigntool.utils.ByteArrayUtils; import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; /** * define class of hap signature block head @@ -31,13 +33,19 @@ public class HwSignHead { public static final int SIGN_HEAD_LEN = 32; private static final char[] MAGIC = "hw signed app ".toCharArray(); // 16Bytes-Magic + + private static final char[] ELF_MAGIC = "elf sign block ".toCharArray(); // 16Bytes-Magic + private static final char[] VERSION = "1000".toCharArray(); // 4-Bytes, version is 1.0.0.0 + private static final int NUM_OF_BLOCK = 2; // number of sub-block + private static final int RESERVE_LENGTH = 4; + private char[] reserve = new char[RESERVE_LENGTH]; /** - * get serialization of HwSignHead + * get serialization of HwSignHead file type of bin * * @param subBlockSize the total size of all sub-blocks * @return Byte array after serialization of HwSignHead @@ -72,4 +80,27 @@ public class HwSignHead { } return signHead; } + + /** + * get serialization of HwSignHead file type of elf + * + * @param subBlockSize the total size of all sub-blocks + * @param subBlockNum the sign block num + * @return Byte array after serialization of HwSignHead + */ + public byte[] getSignHeadLittleEndian(int subBlockSize, int subBlockNum) { + ByteBuffer bf = ByteBuffer.allocate(SIGN_HEAD_LEN).order(ByteOrder.LITTLE_ENDIAN); + for (char c : ELF_MAGIC) { + bf.put((byte) c); + } + for (char c : VERSION) { + bf.put((byte) c); + } + bf.putInt(subBlockSize); + bf.putInt(subBlockNum); + for (char c : reserve) { + bf.put((byte) c); + } + return bf.array(); + } } diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/entity/SignBlockData.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/entity/SignBlockData.java new file mode 100644 index 0000000000000000000000000000000000000000..2ad9874f082283de6f42c1ab2bee9bd95cf96c27 --- /dev/null +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/entity/SignBlockData.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.hapsigntool.hap.entity; + +import com.ohos.hapsigntool.utils.FileUtils; + +/** + * sign block data + * + * @since 2023-11-07 + */ +public class SignBlockData { + private char type; + private byte[] blockHead; + private byte[] signData; + private String signFile; + private long len; + private boolean isByte; + + public SignBlockData(byte[] signData, char type) { + this.signData = signData; + this.type = type; + this.len = signData == null ? 0 : signData.length; + this.isByte = true; + } + + public SignBlockData(String signFile, char type) { + this.signFile = signFile; + this.type = type; + this.len = FileUtils.getFileLen(signFile); + this.isByte = false; + } + + public char getType() { + return type; + } + + public void setType(char type) { + this.type = type; + } + + public byte[] getBlockHead() { + return blockHead; + } + + public void setBlockHead(byte[] blockHead) { + this.blockHead = blockHead; + } + + public byte[] getSignData() { + return signData; + } + + public void setSignData(byte[] signData) { + this.signData = signData; + } + + public String getSignFile() { + return signFile; + } + + public void setSignFile(String signFile) { + this.signFile = signFile; + } + + public long getLen() { + return len; + } + + public void setLen(long len) { + this.len = len; + } + + public boolean isByte() { + return isByte; + } + + public void setByte(boolean isByte) { + this.isByte = isByte; + } +} diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/provider/LocalJKSSignProvider.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/provider/LocalJKSSignProvider.java index 731abb15719b00e6f84d2dc039efbc807455c522..b0e1fa3fb6a0851dddaf2ce08fabb213a01b8cbf 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/provider/LocalJKSSignProvider.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/provider/LocalJKSSignProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -21,6 +21,7 @@ import com.ohos.hapsigntool.hap.exception.MissingParamsException; import com.ohos.hapsigntool.utils.FileUtils; import com.ohos.hapsigntool.utils.ParamConstants; import com.ohos.hapsigntool.utils.ParamProcessUtil; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -87,9 +88,9 @@ public class LocalJKSSignProvider extends SignProvider { public void checkParams(Options options) throws InvalidParamsException, MissingParamsException { super.checkParams(options); String[] paramFileds = { - ParamConstants.PARAM_LOCAL_JKS_KEYSTORE, - ParamConstants.PARAM_LOCAL_JKS_KEYSTORE_CODE, - ParamConstants.PARAM_LOCAL_JKS_KEYALIAS_CODE + ParamConstants.PARAM_LOCAL_JKS_KEYSTORE, + ParamConstants.PARAM_LOCAL_JKS_KEYSTORE_CODE, + ParamConstants.PARAM_LOCAL_JKS_KEYALIAS_CODE }; Set paramSet = ParamProcessUtil.initParamField(paramFileds); @@ -103,7 +104,7 @@ public class LocalJKSSignProvider extends SignProvider { } } } - + checkSignCode(); checkPublicKeyPath(); } } diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/provider/SignProvider.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/provider/SignProvider.java index e5da2793d25edba4ad9865b44d7f2785c1a6523c..4e22f8145df2efc97f4d47fdb6cad06d4d79849b 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/provider/SignProvider.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/provider/SignProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -20,16 +20,20 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonParser; import com.ohos.hapsigntool.api.model.Options; +import com.ohos.hapsigntool.codesigning.exception.CodeSignException; +import com.ohos.hapsigntool.codesigning.exception.FsVerityDigestException; +import com.ohos.hapsigntool.codesigning.sign.CodeSigning; import com.ohos.hapsigntool.error.CustomException; import com.ohos.hapsigntool.hap.config.SignerConfig; import com.ohos.hapsigntool.hap.entity.SigningBlock; +import com.ohos.hapsigntool.hap.exception.HapFormatException; import com.ohos.hapsigntool.hap.exception.InvalidParamsException; import com.ohos.hapsigntool.hap.exception.MissingParamsException; import com.ohos.hapsigntool.hap.exception.ProfileException; import com.ohos.hapsigntool.hap.exception.SignatureException; import com.ohos.hapsigntool.hap.exception.VerifyCertificateChainException; -import com.ohos.hapsigntool.hap.exception.HapFormatException; import com.ohos.hapsigntool.hap.sign.SignBin; +import com.ohos.hapsigntool.hap.sign.SignElf; import com.ohos.hapsigntool.hap.sign.SignHap; import com.ohos.hapsigntool.hap.sign.SignatureAlgorithm; import com.ohos.hapsigntool.hap.verify.VerifyUtils; @@ -60,6 +64,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.StandardCopyOption; @@ -73,9 +78,9 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.TimeZone; -import java.util.Optional; import java.util.jar.JarFile; import java.util.jar.JarOutputStream; @@ -101,6 +106,7 @@ public abstract class SignProvider { VALID_SIGN_ALG_NAME.add(ParamConstants.HAP_SIG_ALGORITHM_SHA256_RSA_MGF1); VALID_SIGN_ALG_NAME.add(ParamConstants.HAP_SIG_ALGORITHM_SHA384_RSA_MGF1); VALID_SIGN_ALG_NAME.add(ParamConstants.HAP_SIG_ALGORITHM_SHA512_RSA_MGF1); + Security.addProvider(new BouncyCastleProvider()); } static { @@ -219,7 +225,7 @@ public abstract class SignProvider { List signatureAlgorithms = new ArrayList(); signatureAlgorithms.add( - ParamProcessUtil.getSignatureAlgorithm(this.signParams.get(ParamConstants.PARAM_BASIC_SIGANTURE_ALG))); + ParamProcessUtil.getSignatureAlgorithm(this.signParams.get(ParamConstants.PARAM_BASIC_SIGANTURE_ALG))); signerConfig.setSignatureAlgorithms(signatureAlgorithms); if (!crl.equals(Optional.empty())) { @@ -235,7 +241,6 @@ public abstract class SignProvider { * @return true, if sign successfully. */ public boolean signBin(Options options) { - Security.addProvider(new BouncyCastleProvider()); List publicCert = null; SignerConfig signerConfig; try { @@ -261,6 +266,44 @@ public abstract class SignProvider { return true; } + /** + * sign elf file + * + * @param options parameters used to sign elf file + * @return true, if sign successfully. + */ + public boolean signElf(Options options) { + List publicCert = null; + SignerConfig signerConfig = null; + try { + publicCert = getX509Certificates(options); + + // Get x509 CRL + Optional crl = getCrl(); + + // Create signer configs, which contains public cert and crl info. + signerConfig = createSignerConfigs(publicCert, crl, options); + } catch (InvalidKeyException | InvalidParamsException | MissingParamsException | ProfileException e) { + LOGGER.error("create signer configs failed.", e); + printErrorLogWithoutStack(e); + return false; + } + + if (ParamConstants.ProfileSignFlag.DISABLE_SIGN_CODE.getSignFlag().equals( + signParams.get(ParamConstants.PARAM_BASIC_PROFILE_SIGNED))) { + LOGGER.error("hap-sign-tool: error: Sign elf can not use unsigned profile."); + return false; + } + + /* 6. make signed file into output file. */ + if (!SignElf.sign(signerConfig, signParams)) { + LOGGER.error("hap-sign-tool: error: Sign elf internal failed."); + return false; + } + LOGGER.info("Sign success"); + return true; + } + /** * sign hap file * @@ -268,7 +311,6 @@ public abstract class SignProvider { * @return true, if sign successfully */ public boolean sign(Options options) { - Security.addProvider(new BouncyCastleProvider()); List publicCerts = null; File output = null; File tmpOutput = null; @@ -279,8 +321,9 @@ public abstract class SignProvider { checkCompatibleVersion(); File input = new File(signParams.get(ParamConstants.PARAM_BASIC_INPUT_FILE)); output = new File(signParams.get(ParamConstants.PARAM_BASIC_OUTPUT_FILE)); + String suffix = getFileSuffix(output); if (input.getCanonicalPath().equals(output.getCanonicalPath())) { - tmpOutput = File.createTempFile("signedHap", ".hap"); + tmpOutput = File.createTempFile("signedHap", "." + suffix); isPathOverlap = true; } else { tmpOutput = output; @@ -295,9 +338,8 @@ public abstract class SignProvider { long centralDirectoryOffset = zipInfo.getCentralDirectoryOffset(); ZipDataInput beforeCentralDir = outputHapIn.slice(0, centralDirectoryOffset); ByteBuffer centralDirBuffer = - outputHapIn.createByteBuffer(centralDirectoryOffset, zipInfo.getCentralDirectorySize()); + outputHapIn.createByteBuffer(centralDirectoryOffset, zipInfo.getCentralDirectorySize()); ZipDataInput centralDirectory = new ByteBufferZipDataInput(centralDirBuffer); - ByteBuffer eocdBuffer = zipInfo.getEocd(); ZipDataInput eocd = new ByteBufferZipDataInput(eocdBuffer); @@ -306,6 +348,7 @@ public abstract class SignProvider { signerConfig.setCompatibleVersion(Integer.parseInt( signParams.get(ParamConstants.PARAM_BASIC_COMPATIBLE_VERSION))); ZipDataInput[] contents = {beforeCentralDir, centralDirectory, eocd}; + appendCodeSignBlock(signerConfig, tmpOutput, suffix, centralDirectoryOffset); byte[] signingBlock = SignHap.sign(contents, signerConfig, optionalBlocks); long newCentralDirectoryOffset = centralDirectoryOffset + signingBlock.length; ZipUtils.setCentralDirectoryOffset(eocdBuffer, newCentralDirectoryOffset); @@ -314,8 +357,8 @@ public abstract class SignProvider { outputSignedFile(outputHap, centralDirectoryOffset, signingBlock, centralDirectory, eocdBuffer); isRet = true; } - } catch (IOException | InvalidKeyException | HapFormatException | MissingParamsException - | InvalidParamsException | ProfileException | NumberFormatException | CustomException e) { + } catch (FsVerityDigestException | InvalidKeyException | HapFormatException | MissingParamsException +|InvalidParamsException |ProfileException |NumberFormatException |CustomException |IOException |CodeSignException e) { printErrorLogWithoutStack(e); } catch (SignatureException e) { printErrorLog(e); @@ -323,6 +366,55 @@ public abstract class SignProvider { return doAfterSign(isRet, isPathOverlap, tmpOutput, output); } + /** + * append code signBlock + * + * @param signerConfig signerConfig + * @param tmpOutput temp output file + * @param suffix suffix + * @param centralDirectoryOffset central directory offset + * @throws FsVerityDigestException FsVerity digest on error + * @throws CodeSignException code sign on error + * @throws IOException IO error + * @throws HapFormatException hap format on error + */ + private void appendCodeSignBlock(SignerConfig signerConfig, File tmpOutput, String suffix, + long centralDirectoryOffset) + throws FsVerityDigestException, CodeSignException, IOException, HapFormatException { + if (signParams.get(ParamConstants.PARAM_SIGN_CODE) + .equals(ParamConstants.SignCodeFlag.ENABLE_SIGN_CODE.getSignCodeFlag())) { + // 4 means hap format occupy 4 byte storage location,2 means optional blocks reserve 2 storage location + int codeSignOffset = (int) + (centralDirectoryOffset + ((4 + 4 + 4) * (optionalBlocks.size() + 2) + (4 + 4 + 4))); + // create CodeSigning Object + CodeSigning codeSigning = new CodeSigning(signerConfig); + byte[] codeSignArray = codeSigning.getCodeSignBlock(tmpOutput, codeSignOffset, suffix); + ByteBuffer result = ByteBuffer.allocate(codeSignArray.length + (4 + 4 + 4)); + result.order(ByteOrder.LITTLE_ENDIAN); + result.putInt(HapUtils.HAP_CODE_SIGN_BLOCK_ID); // type + result.putInt(codeSignArray.length); // length + result.putInt(codeSignOffset); // offset + result.put(codeSignArray); + SigningBlock propertyBlock = new SigningBlock(HapUtils.HAP_PROPERTY_BLOCK_ID, result.array()); + optionalBlocks.add(0, propertyBlock); + } + } + + /** + * obtain file name suffix + * + * @param output output file + * @return suffix + * @throws HapFormatException hap format error + */ + private String getFileSuffix(File output) throws HapFormatException { + String[] fileNameArray = output.getName().split("\\."); + if (fileNameArray.length < ParamConstants.FILE_NAME_MIN_LENGTH) { + throw new HapFormatException("hap format error :" + output); + } + return fileNameArray[fileNameArray.length - 1]; + } + /** * Load certificate chain from input parameters * @@ -341,6 +433,10 @@ public abstract class SignProvider { publicCerts = getPublicCerts(); // 3. load optionalBlocks loadOptionalBlocks(); + if ("elf".equals(options.getString(ParamConstants.PARAM_IN_FORM)) + && StringUtils.isEmpty(options.getString(ParamConstants.PARAM_BASIC_PROFILE))) { + return publicCerts; + } checkProfileValid(publicCerts); return publicCerts; } @@ -353,9 +449,9 @@ public abstract class SignProvider { outputHapOut.write(eocdBuffer); } - private boolean doAfterSign(boolean isSuccess, boolean pathOverlap, File tmpOutput, File output) { + private boolean doAfterSign(boolean isSuccess, boolean isPathOverlap, File tmpOutput, File output) { boolean isRet = isSuccess; - if (isRet && pathOverlap) { + if (isRet && isPathOverlap) { try { Files.move(tmpOutput.toPath(), output.toPath(), StandardCopyOption.REPLACE_EXISTING); } catch (IOException e) { @@ -390,17 +486,18 @@ public abstract class SignProvider { * @param input file input * @param tmpOutput file tmpOutput * @param alignment alignment - * @throws IOException io error + * @throws IOException io error + * @throws HapFormatException hap format error */ - private void copyFileAndAlignment(File input, File tmpOutput, int alignment) throws IOException { + private void copyFileAndAlignment(File input, File tmpOutput, int alignment) + throws IOException, HapFormatException { try (JarFile inputJar = new JarFile(input, false); - FileOutputStream outputFile = new FileOutputStream(tmpOutput); - JarOutputStream outputJar = new JarOutputStream(outputFile)) { + FileOutputStream outputFile = new FileOutputStream(tmpOutput); + JarOutputStream outputJar = new JarOutputStream(outputFile)) { long timestamp = TIMESTAMP; timestamp -= TimeZone.getDefault().getOffset(timestamp); outputJar.setLevel(COMPRESSION_MODE); - List entryNames = SignHap.getEntryNamesFromHap(inputJar); - SignHap.copyFiles(entryNames, inputJar, outputJar, timestamp, alignment); + SignHap.copyFiles(inputJar, outputJar, timestamp, alignment); } } @@ -492,7 +589,7 @@ public abstract class SignProvider { private void checkProfileValid(List inputCerts) throws ProfileException { try { byte[] profile = findProfileFromOptionalBlocks(); - boolean isProfileWithoutSign = ParamConstants.ProfileSignFlag.UNSIGNED_PROFILE.getSignFlag().equals( + boolean isProfileWithoutSign = ParamConstants.ProfileSignFlag.DISABLE_SIGN_CODE.getSignFlag().equals( signParams.get(ParamConstants.PARAM_BASIC_PROFILE_SIGNED)); String content; if (!isProfileWithoutSign) { @@ -536,7 +633,7 @@ public abstract class SignProvider { throw new ProfileException("Unsupported profile type!"); } if (!inputCerts.isEmpty() && !checkInputCertMatchWithProfile(inputCerts.get(0), certInProfile)) { - throw new ProfileException("input certificates do not match with profile!"); + throw new ProfileException("input certificates do not match with profile!"); } String cn = getCertificateCN(certInProfile); LOGGER.info("certificate in profile: {}", cn); @@ -565,18 +662,20 @@ public abstract class SignProvider { */ public void checkParams(Options options) throws MissingParamsException, InvalidParamsException { String[] paramFileds = { - ParamConstants.PARAM_BASIC_ALIGNMENT, - ParamConstants.PARAM_BASIC_SIGANTURE_ALG, - ParamConstants.PARAM_BASIC_INPUT_FILE, - ParamConstants.PARAM_BASIC_OUTPUT_FILE, - ParamConstants.PARAM_BASIC_PRIVATE_KEY, - ParamConstants.PARAM_BASIC_PROFILE, - ParamConstants.PARAM_BASIC_PROOF, - ParamConstants.PARAM_BASIC_PROPERTY, - ParamConstants.PARAM_REMOTE_SERVER, - ParamConstants.PARAM_BASIC_PROFILE_SIGNED, - ParamConstants.PARAM_LOCAL_PUBLIC_CERT, - ParamConstants.PARAM_BASIC_COMPATIBLE_VERSION + ParamConstants.PARAM_BASIC_ALIGNMENT, + ParamConstants.PARAM_BASIC_SIGANTURE_ALG, + ParamConstants.PARAM_BASIC_INPUT_FILE, + ParamConstants.PARAM_BASIC_OUTPUT_FILE, + ParamConstants.PARAM_BASIC_PRIVATE_KEY, + ParamConstants.PARAM_BASIC_PROFILE, + ParamConstants.PARAM_BASIC_PROOF, + ParamConstants.PARAM_BASIC_PROPERTY, + ParamConstants.PARAM_REMOTE_SERVER, + ParamConstants.PARAM_BASIC_PROFILE_SIGNED, + ParamConstants.PARAM_LOCAL_PUBLIC_CERT, + ParamConstants.PARAM_BASIC_COMPATIBLE_VERSION, + ParamConstants.PARAM_SIGN_CODE, + ParamConstants.PARAM_IN_FORM }; Set paramSet = ParamProcessUtil.initParamField(paramFileds); @@ -588,10 +687,29 @@ public abstract class SignProvider { if (!signParams.containsKey(ParamConstants.PARAM_BASIC_PROFILE_SIGNED)) { signParams.put(ParamConstants.PARAM_BASIC_PROFILE_SIGNED, "1"); } + checkSignCode(); checkSignatureAlg(); checkSignAlignment(); } + /** + * Check code sign, if param do not have code sign default "1". + * + * @throws InvalidParamsException invalid param + */ + protected void checkSignCode() throws InvalidParamsException { + if (!signParams.containsKey(ParamConstants.PARAM_SIGN_CODE)) { + signParams.put(ParamConstants.PARAM_SIGN_CODE, + ParamConstants.SignCodeFlag.ENABLE_SIGN_CODE.getSignCodeFlag()); + return; + } + String codeSign = signParams.get(ParamConstants.PARAM_SIGN_CODE); + if (!codeSign.equals(ParamConstants.SignCodeFlag.ENABLE_SIGN_CODE.getSignCodeFlag()) + && !codeSign.equals(ParamConstants.SignCodeFlag.DISABLE_SIGN_CODE.getSignCodeFlag())) { + throw new InvalidParamsException("Invalid parameter: " + ParamConstants.PARAM_SIGN_CODE); + } + } + /** * Check compatible version, if param do not have compatible version default 9. * diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/sign/SignBin.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/sign/SignBin.java index bc94668de46bccd15069f025448f3fe36159d1da..522bf44fc6d4fbc381453b2c755faa4196b3c0c1 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/sign/SignBin.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/sign/SignBin.java @@ -172,7 +172,7 @@ public class SignBin { } HwSignHead signHeadData = new HwSignHead(); byte[] signHeadByte = signHeadData.getSignHead((int) size); - if (signHeadByte == null) { + if (signHeadByte == null || signHeadByte.length == 0) { LOGGER.error("Failed to get sign head data."); return false; } diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/sign/SignElf.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/sign/SignElf.java new file mode 100644 index 0000000000000000000000000000000000000000..811f123979a0a54e032a06aa8187381b7675e999 --- /dev/null +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/sign/SignElf.java @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2023-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.ohos.hapsigntool.hap.sign; + +import com.ohos.hapsigntool.codesigning.exception.CodeSignException; +import com.ohos.hapsigntool.codesigning.exception.FsVerityDigestException; +import com.ohos.hapsigntool.codesigning.sign.CodeSigning; +import com.ohos.hapsigntool.hap.config.SignerConfig; +import com.ohos.hapsigntool.hap.entity.HwBlockHead; +import com.ohos.hapsigntool.hap.entity.HwSignHead; +import com.ohos.hapsigntool.hap.entity.SignBlockData; +import com.ohos.hapsigntool.hap.entity.SignatureBlockTags; +import com.ohos.hapsigntool.hap.entity.SignatureBlockTypes; +import com.ohos.hapsigntool.hap.exception.HapFormatException; +import com.ohos.hapsigntool.utils.FileUtils; +import com.ohos.hapsigntool.utils.ParamConstants; +import com.ohos.hapsigntool.utils.ParamProcessUtil; +import com.ohos.hapsigntool.utils.StringUtils; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * LiteOS bin file Signature signer. + * + * @since 2021/12/21 + */ +public class SignElf { + private static final Logger LOGGER = LogManager.getLogger(SignElf.class); + + private static final String CODESIGN_OFF = "0"; + + private static final char CODESIGN_BLOCK_TYPE = 3; + + private static int blockNum = 0; + + /** + * Constructor of Method + */ + private SignElf() { + } + + /** + * Sign the bin file. + * + * @param signerConfig Config of the bin file to be signed. + * @param signParams The input parameters of sign bin. + * @return true if sign successfully; false otherwise. + */ + public static boolean sign(SignerConfig signerConfig, Map signParams) { + boolean isSuccess = false; + /* 1. Make block head, write to output file. */ + String inputFile = signParams.get(ParamConstants.PARAM_BASIC_INPUT_FILE); + String outputFile = signParams.get(ParamConstants.PARAM_BASIC_OUTPUT_FILE); + String profileSigned = signParams.get(ParamConstants.PARAM_BASIC_PROFILE_SIGNED); + if (!writeBlockDataToFile(signerConfig, inputFile, outputFile, profileSigned, signParams)) { + LOGGER.error("The block head data made failed."); + ParamProcessUtil.delDir(new File(outputFile)); + return false; + } + LOGGER.info("The block head data made success."); + + /* 2. Make sign data, and write to output file */ + if (!writeSignHeadDataToOutputFile(inputFile, outputFile, blockNum)) { + LOGGER.error("The sign head data made failed."); + ParamProcessUtil.delDir(new File(outputFile)); + } else { + isSuccess = true; + } + return isSuccess; + } + + private static boolean writeBlockDataToFile(SignerConfig signerConfig, + String inputFile, String outputFile, String profileSigned, Map signParams) { + try { + String profileFile = signParams.get(ParamConstants.PARAM_BASIC_PROFILE); + + List signDataList = new ArrayList<>(); + + long binFileLen = FileUtils.getFileLen(inputFile); + if (binFileLen == -1) { + LOGGER.error("file length is invalid, bin file len: " + binFileLen); + throw new IOException(); + } + // 1. generate sign data + if (!StringUtils.isEmpty(signParams.get(ParamConstants.PARAM_BASIC_PROFILE))) { + signDataList.add(generateProfileSignByte(profileFile, profileSigned)); + } + blockNum = signDataList.size(); + SignBlockData codeSign = generateCodeSignByte(signerConfig, signParams, inputFile, blockNum, binFileLen); + if (codeSign != null) { + signDataList.add(0, codeSign); + } + blockNum = signDataList.size(); + // 2. use sign data generate offset and sign block head + generateSignBlockHead(signDataList); + + return writeSignedElf(inputFile, signDataList, outputFile); + } catch (IOException e) { + LOGGER.error("writeBlockDataToFile failed.", e); + return false; + } catch (FsVerityDigestException | CodeSignException | HapFormatException e) { + LOGGER.error("codesign failed.", e); + return false; + } + } + + private static boolean writeSignedElf(String inputFile, List signBlockList, String outputFile) { + try (FileOutputStream fileOutputStream = new FileOutputStream(outputFile); + DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream)) { + // 1. write the input file to the output file. + if (!FileUtils.writeFileToDos(inputFile, dataOutputStream)) { + LOGGER.error("Failed to write information of input file: " + inputFile + + " to outputFile: " + outputFile); + throw new IOException(); + } + + // 2. write block head to the output file. + for (SignBlockData signBlockData : signBlockList) { + if (!FileUtils.writeByteToDos(signBlockData.getBlockHead(), dataOutputStream)) { + LOGGER.error("Failed to write Block Head to output file: " + outputFile); + throw new IOException(); + } + } + + // 3. write block data to the output file. + for (SignBlockData signBlockData : signBlockList) { + boolean isSuccess; + if (signBlockData.isByte()) { + isSuccess = FileUtils.writeByteToDos(signBlockData.getSignData(), dataOutputStream); + } else { + isSuccess = FileUtils.writeFileToDos(signBlockData.getSignFile(), dataOutputStream); + } + + if (!isSuccess) { + LOGGER.error("Failed to write Block Data to output file: " + outputFile); + throw new IOException(); + } + } + } catch (IOException e) { + LOGGER.error("writeSignedBin failed.", e); + return false; + } + return true; + } + + private static void generateSignBlockHead(List signDataList) + throws IOException { + long offset = (long) HwBlockHead.getElfBlockLen() * signDataList.size(); + + for (int i = 0; i < signDataList.size(); i++) { + SignBlockData signBlockData = signDataList.get(i); + + signBlockData.setBlockHead(HwBlockHead.getBlockHeadLittleEndian(signBlockData.getType(), + SignatureBlockTags.DEFAULT, (int) signBlockData.getLen(), (int) offset)); + offset += signBlockData.getLen(); + if (isLongOverflowInteger(offset)) { + LOGGER.error("The sign block " + i + "offset is overflow integer, offset: " + offset); + throw new IOException(); + } + } + } + + private static SignBlockData generateProfileSignByte(String profileFile, String profileSigned) throws IOException { + long profileDataLen = FileUtils.getFileLen(profileFile); + + if (profileDataLen == -1 || isLongOverflowShort(profileDataLen)) { + LOGGER.error("file length is invalid, profileDataLen: " + profileDataLen); + throw new IOException(); + } + + char isSigned = SignatureBlockTypes.getProfileBlockTypes(profileSigned); + return new SignBlockData(profileFile, isSigned); + } + + private static SignBlockData generateCodeSignByte(SignerConfig signerConfig, Map signParams, + String inputFile, int blockNum, long binFileLen) throws IOException, + FsVerityDigestException, CodeSignException, HapFormatException { + if (CODESIGN_OFF.equals(signParams.get(ParamConstants.PARAM_SIGN_CODE))) { + return null; + } + CodeSigning codeSigning = new CodeSigning(signerConfig); + long offset = binFileLen + (long) HwBlockHead.getElfBlockLen() * blockNum; + byte[] codesignData = codeSigning.getCodeSignBlock(new File(inputFile), offset, + signParams.get(ParamConstants.PARAM_IN_FORM)); + return new SignBlockData(codesignData, CODESIGN_BLOCK_TYPE); + } + + private static boolean writeSignHeadDataToOutputFile(String inputFile, String outputFile, int blockNum) { + long size = FileUtils.getFileLen(outputFile) - FileUtils.getFileLen(inputFile); + if (isLongOverflowInteger(size)) { + LOGGER.error("File size is Overflow integer range."); + return false; + } + HwSignHead signHeadData = new HwSignHead(); + byte[] signHeadByte = signHeadData.getSignHeadLittleEndian((int) size, blockNum); + if (signHeadByte == null) { + LOGGER.error("Failed to get sign head data."); + return false; + } + return FileUtils.writeByteToOutFile(signHeadByte, outputFile); + } + + private static boolean isLongOverflowInteger(long num) { + return (num - (num & 0xffffffffL)) != 0; + } + + private static boolean isLongOverflowShort(long num) { + return (num - (num & 0xffffL)) != 0; + } +} diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/sign/SignHap.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/sign/SignHap.java index eede0eaab64946ffd2011a6bd7bfcc4e20fd9e18..6cce8549cc295235d7d7719b6b087889ae735609 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/sign/SignHap.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/sign/SignHap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -19,8 +19,10 @@ import com.ohos.hapsigntool.api.model.Options; import com.ohos.hapsigntool.hap.config.SignerConfig; import com.ohos.hapsigntool.hap.entity.Pair; import com.ohos.hapsigntool.hap.entity.SigningBlock; +import com.ohos.hapsigntool.hap.exception.HapFormatException; import com.ohos.hapsigntool.hap.exception.SignatureException; import com.ohos.hapsigntool.utils.HapUtils; +import com.ohos.hapsigntool.utils.StringUtils; import com.ohos.hapsigntool.zip.ZipDataInput; import java.io.IOException; @@ -29,8 +31,6 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.security.DigestException; import java.util.ArrayList; -import java.util.Collections; -import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -39,8 +39,10 @@ import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.JarOutputStream; +import java.util.stream.Collectors; /** + * * Hap Signature Scheme signer * * @since 2021/12/21 @@ -63,96 +65,168 @@ public abstract class SignHap { return BLOCK_SIZE; } - /** - * Get all entries' name from hap which is opened as a jar-file. - * - * @param hap input hap-file which is opened as a jar-file. - * @return list of entries' names. - */ - public static List getEntryNamesFromHap(JarFile hap) { - List result = new ArrayList(); - for (Enumeration e = hap.entries(); e.hasMoreElements();) { - JarEntry entry = e.nextElement(); - if (!entry.isDirectory()) { - result.add(entry.getName()); - } - } - return result; - } - /** * Copy the jar file and align the storage entries. * - * @param entryNames list of entries' name * @param in input hap-file which is opened as a jar-file. * @param out output stream of jar. * @param timestamp ZIP file timestamps * @param defaultAlignment default value of alignment. * @throws IOException io error. + * @throws HapFormatException hap format error. */ - public static void copyFiles(List entryNames, JarFile in, - JarOutputStream out, long timestamp, int defaultAlignment) throws IOException { - Collections.sort(entryNames); + public static void copyFiles(JarFile in, + JarOutputStream out, long timestamp, int defaultAlignment) throws IOException, HapFormatException { + // split compressed and uncompressed + List entryListStored = in.stream() + .filter(jarFile -> jarFile.getMethod() == JarEntry.STORED).collect(Collectors.toList()); + + // uncompressed special files and place in front + entryListStored = storedEntryListOfSort(entryListStored); long offset = INIT_OFFSET_LEN; - for (String name : entryNames) { - JarEntry inEntry = in.getJarEntry(name); - if (inEntry.getMethod() != JarEntry.STORED) { + String lastAlignmentEntryName = ""; + for (JarEntry inEntry : entryListStored) { + String entryName = inEntry.getName(); + if (!(entryName.endsWith(".so")) && !(entryName.endsWith(".abc"))) { + lastAlignmentEntryName = entryName; + break; + } + } + for (JarEntry inEntry : entryListStored) { + if (inEntry == null) { continue; } offset += JarFile.LOCHDR; - JarEntry outEntry = new JarEntry(inEntry); - outEntry.setTime(timestamp); - - outEntry.setComment(null); - outEntry.setExtra(null); - + JarEntry outEntry = getJarEntry(timestamp, inEntry); offset += outEntry.getName().length(); - int alignment = getStoredEntryDataAlignment(name, defaultAlignment); + int alignment = getStoredEntryDataAlignment(inEntry.getName(), defaultAlignment, lastAlignmentEntryName); if (alignment > 0 && (offset % alignment != 0)) { int needed = alignment - (int) (offset % alignment); outEntry.setExtra(new byte[needed]); offset += needed; } + out.putNextEntry(outEntry); + offset = writeOutputStreamAndGetOffset(in, out, inEntry, offset); + } + List entryListNotStored = in.stream() + .filter(jarFile -> jarFile.getMethod() != JarEntry.STORED).collect(Collectors.toList()); + // process byte alignment of the first compressed file + boolean isAlignmentFlag = StringUtils.isEmpty(lastAlignmentEntryName); + if (isAlignmentFlag) { + if (entryListNotStored.isEmpty()) { + throw new HapFormatException("Hap format is error, file missing"); + } + JarEntry firstEntry = entryListNotStored.get(0); + offset += JarFile.LOCHDR; + JarEntry outEntry = getFirstJarEntry(firstEntry, offset, timestamp); out.putNextEntry(outEntry); byte[] buffer = new byte[BUFFER_LENGTH]; - try (InputStream data = in.getInputStream(inEntry)) { - int num; - while ((num = data.read(buffer)) > 0) { - out.write(buffer, 0, num); - offset += num; - } - out.flush(); + writeOutputStream(in, out, firstEntry, buffer); + } + + copyFilesExceptStoredFile(entryListNotStored, in, out, timestamp, isAlignmentFlag); + } + + /** + * uncompressed special files are placed in front + * + * @param entryListStored stored file entry list + * @return List jarEntryList + */ + private static List storedEntryListOfSort(List entryListStored) { + return entryListStored.stream().sorted((entry1, entry2) -> { + String name1 = entry1.getName(); + String name2 = entry2.getName(); + // files ending with .abc or .so are placed before other files + boolean isSpecial1 = name1.endsWith(".abc") || name1.endsWith(".so"); + boolean isSpecial2 = name2.endsWith(".abc") || name2.endsWith(".so"); + if (isSpecial1 && !isSpecial2) { + return -1; + } else if (!isSpecial1 && isSpecial2) { + return 1; + } else { + // if all files are special files or none of them are special files,the files are sorted lexically + return name1.compareTo(name2); } + }).collect(Collectors.toList()); + } + + private static JarEntry getFirstJarEntry(JarEntry firstEntry, long offset, long timestamp) { + long currentOffset = offset; + JarEntry outEntry = getJarEntry(timestamp, firstEntry); + currentOffset += outEntry.getName().length(); + if (currentOffset % STORED_ENTRY_SO_ALIGNMENT != 0) { + int needed = STORED_ENTRY_SO_ALIGNMENT - (int) (currentOffset % STORED_ENTRY_SO_ALIGNMENT); + outEntry.setExtra(new byte[needed]); } + return outEntry; + } - copyFilesExceptStoredFile(entryNames, in, out, timestamp); + /** + * write first not stored entry to outputStream + * + * @param in jar file + * @param out jarOutputStream + * @param firstEntry jarEntry + * @param buffer byte[] + * @throws IOException IOExpcetion + */ + private static void writeOutputStream(JarFile in, JarOutputStream out, JarEntry firstEntry, byte[] buffer) + throws IOException { + try (InputStream data = in.getInputStream(firstEntry)) { + int num; + while ((num = data.read(buffer)) > 0) { + out.write(buffer, 0, num); + } + out.flush(); + } } - private static void copyFilesExceptStoredFile(List entryNames, JarFile in, - JarOutputStream out, long timestamp) throws IOException { + private static long writeOutputStreamAndGetOffset(JarFile in, JarOutputStream out, JarEntry inEntry, long offset) + throws IOException { byte[] buffer = new byte[BUFFER_LENGTH]; + long currentOffset = offset; + try (InputStream data = in.getInputStream(inEntry)) { + int num; + while ((num = data.read(buffer)) > 0) { + out.write(buffer, 0, num); + currentOffset += num; + } + out.flush(); + } + return currentOffset; + } + + private static JarEntry getJarEntry(long timestamp, JarEntry inEntry) { + JarEntry outEntry = new JarEntry(inEntry); + outEntry.setTime(timestamp); - for (String name : entryNames) { - JarEntry inEntry = in.getJarEntry(name); - if (inEntry.getMethod() == JarEntry.STORED) { + outEntry.setComment(null); + outEntry.setExtra(null); + return outEntry; + } + + private static void copyFilesExceptStoredFile(List entryListNotStored, JarFile in, + JarOutputStream out, long timestamp, boolean isAlignmentFlag) throws IOException { + byte[] buffer = new byte[BUFFER_LENGTH]; + int index = 0; + if (isAlignmentFlag) { + index = 1; + } + for (; index < entryListNotStored.size(); index++) { + JarEntry inEntry = entryListNotStored.get(index); + if (inEntry == null || inEntry.getMethod() == JarEntry.STORED) { continue; } - JarEntry outEntry = new JarEntry(name); + JarEntry outEntry = new JarEntry(inEntry.getName()); outEntry.setTime(timestamp); out.putNextEntry(outEntry); - - try (InputStream data = in.getInputStream(inEntry);) { - int num; - while ((num = data.read(buffer)) > 0) { - out.write(buffer, 0, num); - } - out.flush(); - } + writeOutputStream(in, out, inEntry, buffer); } } @@ -161,13 +235,18 @@ public abstract class SignHap { * * @param entryName name of entry * @param defaultAlignment default value of alignment. + * @param lastAlignmentEntryName lastAlignmentEntryName * @return value of alignment. */ - private static int getStoredEntryDataAlignment(String entryName, int defaultAlignment) { + private static int getStoredEntryDataAlignment(String entryName, int defaultAlignment, + String lastAlignmentEntryName) { if (defaultAlignment <= 0) { return 0; } - if (entryName.endsWith(".so")) { + if (!StringUtils.isEmpty(lastAlignmentEntryName) && entryName.equals(lastAlignmentEntryName)) { + return STORED_ENTRY_SO_ALIGNMENT; + } + if (entryName.endsWith(".so") || entryName.endsWith("abc")) { return STORED_ENTRY_SO_ALIGNMENT; } return defaultAlignment; @@ -178,7 +257,7 @@ public abstract class SignHap { List optionalBlocks, SignerConfig signerConfig, ZipDataInput[] hapData) - throws SignatureException { + throws SignatureException { /** * Compute digests of Hap contents * Sign the digests and wrap the signature and signer info into the Hap Signing Block @@ -186,7 +265,7 @@ public abstract class SignHap { byte[] hapSignatureBytes = null; try { Map contentDigests = - HapUtils.computeDigests(contentDigestAlgorithms, hapData, optionalBlocks); + HapUtils.computeDigests(contentDigestAlgorithms, hapData, optionalBlocks); hapSignatureBytes = generateHapSigningBlock(signerConfig, contentDigests, optionalBlocks); } catch (DigestException | IOException e) { throw new SignatureException("Failed to compute digests of HAP", e); @@ -204,35 +283,29 @@ public abstract class SignHap { } private static byte[] generateHapSigningBlock(byte[] hapSignatureSchemeBlock, - List optionalBlocks, int compatibleVersion) { + List optionalBlocks, int compatibleVersion) { // 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 - - // uint32: block count // uint64: size // uint128: magic // uint32: version @@ -240,7 +313,6 @@ public abstract class SignHap { for (SigningBlock optionalBlock : optionalBlocks) { optionalBlockSize += optionalBlock.getLength(); } - long resultSize = ((OPTIONAL_TYPE_SIZE + OPTIONAL_LENGTH_SIZE + OPTIONAL_OFFSET_SIZE) * (optionalBlocks.size() + 1)) + optionalBlockSize // optional pair @@ -256,8 +328,8 @@ public abstract class SignHap { result.order(ByteOrder.LITTLE_ENDIAN); Map typeAndOffsetMap = new HashMap(); - int currentOffset = ((OPTIONAL_TYPE_SIZE + OPTIONAL_LENGTH_SIZE + - OPTIONAL_OFFSET_SIZE) * (optionalBlocks.size() + 1)); + int currentOffset = ((OPTIONAL_TYPE_SIZE + OPTIONAL_LENGTH_SIZE + + OPTIONAL_OFFSET_SIZE) * (optionalBlocks.size() + 1)); int currentOffsetInBlockValue = 0; int blockValueSizes = (int) (optionalBlockSize + hapSignatureSchemeBlock.length); byte[] blockValues = new byte[blockValueSizes]; @@ -274,20 +346,12 @@ public abstract class SignHap { hapSignatureSchemeBlock, 0, blockValues, currentOffsetInBlockValue, hapSignatureSchemeBlock.length); typeAndOffsetMap.put(HapUtils.HAP_SIGNATURE_SCHEME_V1_BLOCK_ID, currentOffset); - int offset = 0; - for (SigningBlock optionalBlock : optionalBlocks) { - result.putInt(optionalBlock.getType()); // type - result.putInt(optionalBlock.getLength()); // length - offset = typeAndOffsetMap.get(optionalBlock.getType()); - result.putInt(offset); // offset - } + extractedResult(optionalBlocks, result, typeAndOffsetMap); result.putInt(HapUtils.HAP_SIGNATURE_SCHEME_V1_BLOCK_ID); // type result.putInt(hapSignatureSchemeBlock.length); // length - offset = typeAndOffsetMap.get(HapUtils.HAP_SIGNATURE_SCHEME_V1_BLOCK_ID); + int offset = typeAndOffsetMap.get(HapUtils.HAP_SIGNATURE_SCHEME_V1_BLOCK_ID); result.putInt(offset); // offset - result.put(blockValues); - result.putInt(optionalBlocks.size() + 1); // Signing block count result.putLong(resultSize); // length of hap signing block result.put(HapUtils.getHapSigningBlockMagic(compatibleVersion)); // magic @@ -295,6 +359,17 @@ public abstract class SignHap { return result.array(); } + private static void extractedResult(List optionalBlocks, ByteBuffer result, + Map typeAndOffsetMap) { + int offset; + for (SigningBlock optionalBlock : optionalBlocks) { + result.putInt(optionalBlock.getType()); // type + result.putInt(optionalBlock.getLength()); // length + offset = typeAndOffsetMap.get(optionalBlock.getType()); + result.putInt(offset); // offset + } + } + private static byte[] generateHapSignatureSchemeBlock( SignerConfig signerConfig, Map contentDigests) throws SignatureException { byte[] signerBlock = null; @@ -310,7 +385,7 @@ public abstract class SignHap { SignerConfig signerConfig, Map contentDigests) throws SignatureException { String mode = signerConfig.getOptions().getString(Options.MODE); if (!("remoteSign".equalsIgnoreCase(mode)) && signerConfig.getCertificates().isEmpty()) { - throw new SignatureException("No certificates configured for signer"); + throw new SignatureException("No certificates configured for signer"); } List> digests = @@ -342,7 +417,7 @@ public abstract class SignHap { * @throws SignatureException if an error occurs when sign hap file. */ public static byte[] sign(ZipDataInput[] contents, SignerConfig signerConfig, List optionalBlocks) - throws SignatureException { + throws SignatureException { Set contentDigestAlgorithms = new HashSet(); for (SignatureAlgorithm signatureAlgorithm : signerConfig.getSignatureAlgorithms()) { contentDigestAlgorithms.add(signatureAlgorithm.getContentDigestAlgorithm()); diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/verify/HapVerify.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/verify/HapVerify.java index abfb465b46bd6e8263c11c1b473000eba997d5f6..db6eec7d04ccc2bb5f4613025f9776878afcda33 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/verify/HapVerify.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/verify/HapVerify.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -91,7 +91,7 @@ public class HapVerify { private JcaX509CRLConverter crlConverter = new JcaX509CRLConverter(); - private boolean printCert; + private boolean isPrintCert; public HapVerify( ZipDataInput beforeApkSigningBlock, @@ -115,12 +115,12 @@ public class HapVerify { return parserSigner(signatureSchemeBlock); } - public void setPrintCert(boolean printCert) { - this.printCert = printCert; + public void setIsPrintCert(boolean isPrintCert) { + this.isPrintCert = isPrintCert; } private boolean checkCRL(X509CRL crl, List certificates) { - boolean ret = false; + boolean isRet = false; for (X509Certificate cert : certificates) { if (!crl.getIssuerDN().getName().equals(cert.getIssuerDN().getName())) { continue; @@ -129,12 +129,12 @@ public class HapVerify { if (entry != null) { LOGGER.info("cert(subject DN = {}) is revoked by crl (IssuerDN = {})", cert.getSubjectDN().getName(), crl.getIssuerDN().getName()); - ret = false; + isRet = false; break; } - ret = true; + isRet = true; } - return ret; + return isRet; } private boolean verifyCRL(X509CRL crl, X509Certificate cert, List certificates) @@ -152,33 +152,33 @@ public class HapVerify { } private boolean verifyCRL(X509CRL crl, List certificates) throws SignatureException { - boolean revoked = true; + boolean isRevoked = true; for (X509Certificate cert : certificates) { if (!crl.getIssuerDN().getName().equals(cert.getSubjectDN().getName())) { continue; } if (!verifyCRL(crl, cert, certificates)) { - revoked = false; + isRevoked = false; } } - return revoked; + return isRevoked; } private void verifyCRLs(List crls, List certificates) throws VerifyHapException { if (crls == null) { return; } - boolean revoked = true; + boolean isRevoked = true; try { for (X509CRL crl : crls) { if (!verifyCRL(crl, certificates)) { - revoked = false; + isRevoked = false; } } } catch (SignatureException e) { throw new VerifyHapException("Verify CRL error!", e); } - if (!revoked) { + if (!isRevoked) { throw new VerifyHapException("Certificate is revoked!"); } } @@ -186,8 +186,8 @@ public class HapVerify { private CMSSignedData verifyCmsSignedData(byte[] signingBlock) throws VerifyHapException { try { CMSSignedData cmsSignedData = new CMSSignedData(signingBlock); - boolean verifyResult = VerifyUtils.verifyCmsSignedData(cmsSignedData); - if (!verifyResult) { + boolean isVerifyResult = VerifyUtils.verifyCmsSignedData(cmsSignedData); + if (!isVerifyResult) { throw new VerifyHapException("Verify PKCS7 cms data failed!"); } return cmsSignedData; @@ -238,8 +238,8 @@ public class HapVerify { throw new VerifyHapException("PKCS cms content is not a byte array!"); } try { - boolean checkResult = parserContentinfo(contentBytes); - if (!checkResult) { + boolean isCheckResult = parserContentinfo(contentBytes); + if (!isCheckResult) { throw new VerifyHapException("Hap content digest check failed."); } } catch (DigestException | SignatureException | IOException e) { @@ -254,7 +254,7 @@ public class HapVerify { if (certificateList == null || certificateList.size() == 0) { throw new VerifyHapException("Certificate chain is empty!"); } - if (printCert) { + if (isPrintCert) { for (int i = 0; i < certificateList.size(); i++) { LOGGER.info("+++++++++++++++++++++++++++certificate #{} +++++++++++++++++++++++++++++++", i); printCert(certificateList.get(i)); @@ -289,7 +289,7 @@ public class HapVerify { } private List certStoreToCertList(Store certificates) - throws CertificateException { + throws CertificateException { if (certificates == null) { return Collections.emptyList(); } @@ -308,7 +308,6 @@ public class HapVerify { private boolean parserContentinfo(byte[] data) throws DigestException, SignatureException, IOException { - boolean result = true; ByteBuffer digestDatas = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN); while (digestDatas.remaining() > 4) { /** @@ -344,22 +343,22 @@ public class HapVerify { Set keySet = digestMap.keySet(); Map actualDigestMap = HapUtils.computeDigests( keySet, new ZipDataInput[]{beforeApkSigningBlock, centralDirectoryBlock, eocd}, optionalBlocks); - + boolean isResult = true; for (Entry entry : digestMap.entrySet()) { ContentDigestAlgorithm digestAlg = entry.getKey(); byte[] exceptDigest = entry.getValue(); byte[] actualDigest = actualDigestMap.get(digestAlg); if (!Arrays.equals(actualDigest, exceptDigest)) { - result = false; + isResult = false; LOGGER.error( - "degist data do not match! DigestAlgorithm: {}, actualDigest: <{}> VS exceptDigest : <{}>", - digestAlg.getDigestAlgorithm(), - HapUtils.toHex(actualDigest, ""), - HapUtils.toHex(exceptDigest, "")); + "degist data do not match! DigestAlgorithm: {}, actualDigest: <{}> VS exceptDigest : <{}>", + digestAlg.getDigestAlgorithm(), + HapUtils.toHex(actualDigest, ""), + HapUtils.toHex(exceptDigest, "")); } - LOGGER.info("Digest verify result: {}, DigestAlgorithm: {}", result, digestAlg.getDigestAlgorithm()); + LOGGER.info("Digest verify result: {}, DigestAlgorithm: {}", isResult, digestAlg.getDigestAlgorithm()); } - return result; + return isResult; } private void printCert(X509Certificate cert) throws CertificateEncodingException { diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/verify/VerifyHap.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/verify/VerifyHap.java index c5c5834cd78020f1436df6da0773e29b6104fc07..e5d893bc150d4d3bf20574f681374778e3eb32a9 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/verify/VerifyHap.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/verify/VerifyHap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -16,6 +16,9 @@ package com.ohos.hapsigntool.hap.verify; import com.ohos.hapsigntool.api.model.Options; +import com.ohos.hapsigntool.codesigning.exception.FsVerityDigestException; +import com.ohos.hapsigntool.codesigning.exception.VerifyCodeSignException; +import com.ohos.hapsigntool.codesigning.sign.VerifyCodeSignature; import com.ohos.hapsigntool.hap.entity.Pair; import com.ohos.hapsigntool.hap.entity.SigningBlock; import com.ohos.hapsigntool.hap.exception.HapFormatException; @@ -32,6 +35,7 @@ import com.ohos.hapsigntool.zip.ZipUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.bouncycastle.cms.CMSException; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.jcajce.JcaPEMWriter; import org.bouncycastle.util.Arrays; @@ -49,11 +53,13 @@ import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * Class of verify hap. * - * @2021/12/23 + * @since 2021/12/23 */ public class VerifyHap { private static final Logger LOGGER = LogManager.getLogger(VerifyHap.class); @@ -61,18 +67,18 @@ public class VerifyHap { private static final int ZIP_HEAD_OF_SIGNING_BLOCK_COUNT_OFFSET_REVERSE = 28; private static final int ZIP_HEAD_OF_SUBSIGNING_BLOCK_LENGTH = 12; - private final boolean printCert; + static { + Security.addProvider(new BouncyCastleProvider()); + } + + private final boolean isPrintCert; public VerifyHap() { this(true); } - public VerifyHap(boolean printCert) { - this.printCert = printCert; - } - - static { - Security.addProvider(new BouncyCastleProvider()); + public VerifyHap(boolean isPrintCert) { + this.isPrintCert = isPrintCert; } /** @@ -110,7 +116,6 @@ public class VerifyHap { throw new IOException(); } String filePath = options.getString(ParamConstants.PARAM_BASIC_INPUT_FILE); - String outputCertPath = options.getString(ParamConstants.PARAM_VERIFY_CERTCHAIN_FILE); if (StringUtils.isEmpty(filePath)) { LOGGER.error("Not found verify file path!"); throw new IOException(); @@ -125,7 +130,7 @@ public class VerifyHap { LOGGER.error("verify: {}", verifyResult.getMessage()); throw new IOException(); } - + String outputCertPath = options.getString(ParamConstants.PARAM_VERIFY_CERTCHAIN_FILE); writeCertificate(outputCertPath, verifyResult.getCertificates()); } catch (IOException e) { LOGGER.error("Write certificate chain error", e); @@ -157,7 +162,7 @@ public class VerifyHap { } private void outputOptionalBlocks(String outputProfileFile, String outputProofFile, String outputPropertyFile, - VerifyResult verifyResult) throws IOException { + VerifyResult verifyResult) throws IOException { List optionalBlocks = verifyResult.getOptionalBlocks(); if (optionalBlocks != null && optionalBlocks.size() > 0) { for (SigningBlock optionalBlock : optionalBlocks) { @@ -218,7 +223,7 @@ public class VerifyHap { outputOptionalBlocks(outProvisionFile, null, null, verifyResult); } catch (IOException e) { LOGGER.error("Write certificate chain or profile error", e); - verifyResult.setResult(false); + verifyResult.setIsResult(false); return verifyResult; } return verifyResult; @@ -248,16 +253,12 @@ public class VerifyHap { ByteBuffer signatureSchemeBlock = blockPair.getFirst(); List optionalBlocks = blockPair.getSecond(); Collections.reverse(optionalBlocks); - long signingBlockOffset = hapSigningBlockAndOffsetInFile.getOffset(); - ZipDataInput beforeHapSigningBlock = hapFile.slice(0, signingBlockOffset); - ZipDataInput centralDirectoryBlock = hapFile.slice(zipInfo.getCentralDirectoryOffset(), - zipInfo.getCentralDirectorySize()); - ByteBuffer eocdBbyteBuffer = zipInfo.getEocd(); - ZipUtils.setCentralDirectoryOffset(eocdBbyteBuffer, signingBlockOffset); - ZipDataInput eocdBlock = new ByteBufferZipDataInput(eocdBbyteBuffer); - HapVerify verifyEngine = new HapVerify(beforeHapSigningBlock, signatureSchemeBlock, - centralDirectoryBlock, eocdBlock, optionalBlocks); - verifyEngine.setPrintCert(printCert); + if (!checkCodeSign(hapFilePath, optionalBlocks)) { + String errMsg = "ZIP64 code sign data error"; + return new VerifyResult(false, VerifyResult.RET_CODESIGN_DATA_ERROR, errMsg); + } + HapVerify verifyEngine = getHapVerify(hapFile, zipInfo, hapSigningBlockAndOffsetInFile, + signatureSchemeBlock, optionalBlocks); result = verifyEngine.verify(); result.setSignBlockVersion(hapSigningBlockAndOffsetInFile.getVersion()); } catch (IOException e) { @@ -269,19 +270,87 @@ public class VerifyHap { } catch (HapFormatException e) { LOGGER.error("Verify Hap failed, unsupported format hap.", e); result = new VerifyResult(false, VerifyResult.RET_UNSUPPORTED_FORMAT_ERROR, e.getMessage()); + } catch (FsVerityDigestException e) { + LOGGER.error("Verify Hap failed, fs-verity digest generate failed.", e); + result = new VerifyResult(false, VerifyResult.RET_DIGEST_ERROR, e.getMessage()); + } catch (VerifyCodeSignException e) { + LOGGER.error("Verify Hap failed, code sign block verify failed.", e); + result = new VerifyResult(false, VerifyResult.RET_CODE_SIGN_BLOCK_ERROR, e.getMessage()); + } catch (CMSException e) { + LOGGER.error("Verify Hap failed, code signature verify failed.", e); + result = new VerifyResult(false, VerifyResult.RET_SIGNATURE_ERROR, e.getMessage()); } return result; } + private HapVerify getHapVerify(ZipDataInput hapFile, ZipFileInfo zipInfo, + HapUtils.HapSignBlockInfo hapSigningBlockAndOffsetInFile, + ByteBuffer signatureSchemeBlock, List optionalBlocks) { + long signingBlockOffset = hapSigningBlockAndOffsetInFile.getOffset(); + ZipDataInput beforeHapSigningBlock = hapFile.slice(0, signingBlockOffset); + ZipDataInput centralDirectoryBlock = hapFile.slice(zipInfo.getCentralDirectoryOffset(), + zipInfo.getCentralDirectorySize()); + ByteBuffer eocdBbyteBuffer = zipInfo.getEocd(); + ZipUtils.setCentralDirectoryOffset(eocdBbyteBuffer, signingBlockOffset); + ZipDataInput eocdBlock = new ByteBufferZipDataInput(eocdBbyteBuffer); + HapVerify verifyEngine = new HapVerify(beforeHapSigningBlock, signatureSchemeBlock, + centralDirectoryBlock, eocdBlock, optionalBlocks); + verifyEngine.setIsPrintCert(isPrintCert); + return verifyEngine; + } + + /** + * code sign check + * + * @param hapFilePath hap file path + * @param optionalBlocks optional blocks + * @return true or false + * @throws FsVerityDigestException FsVerity digest on error + * @throws IOException IO error + * @throws VerifyCodeSignException verify code sign on error + * @throws CMSException cms on error + */ + private boolean checkCodeSign(String hapFilePath, List optionalBlocks) + throws FsVerityDigestException, IOException, VerifyCodeSignException, CMSException { + Map map = optionalBlocks.stream() + .collect(Collectors.toMap(SigningBlock::getType, SigningBlock::getValue)); + byte[] propertyBlockArray = map.get(HapUtils.HAP_PROPERTY_BLOCK_ID); + if (propertyBlockArray != null && propertyBlockArray.length > 0) { + String[] fileNameArray = hapFilePath.split("\\."); + if (fileNameArray.length < ParamConstants.FILE_NAME_MIN_LENGTH) { + LOGGER.error("ZIP46 format not supported"); + return false; + } + ByteBuffer byteBuffer = ByteBuffer.wrap(propertyBlockArray); + String suffix = fileNameArray[fileNameArray.length - 1]; + ByteBuffer header = HapUtils.reverseSliceBuffer(byteBuffer, 0, ZIP_HEAD_OF_SUBSIGNING_BLOCK_LENGTH); + int blockOffset = header.getInt(); + int blockLength = header.getInt(); + int blockType = header.getInt(); + if (blockType != HapUtils.HAP_CODE_SIGN_BLOCK_ID) { + LOGGER.error("Verify Hap has no code sign data error!"); + return false; + } + File outputFile = new File(hapFilePath); + boolean isCodeSign = VerifyCodeSignature.verifyHap(outputFile, blockOffset, blockLength, suffix); + if (!isCodeSign) { + LOGGER.error("Verify Hap has no code sign data error!"); + return false; + } + return true; + } + return true; + } + private Pair> getHapSignatureSchemeBlockAndOptionalBlocks(ByteBuffer hapSigningBlock) throws SignatureNotFoundException { try { ByteBuffer header = HapUtils.reverseSliceBuffer( - hapSigningBlock, - hapSigningBlock.capacity() - ZIP_HEAD_OF_SIGNING_BLOCK_LENGTH, - hapSigningBlock.capacity()); + hapSigningBlock, + hapSigningBlock.capacity() - ZIP_HEAD_OF_SIGNING_BLOCK_LENGTH, + hapSigningBlock.capacity()); ByteBuffer value = HapUtils.reverseSliceBuffer(hapSigningBlock, 0, - hapSigningBlock.capacity() - ZIP_HEAD_OF_SIGNING_BLOCK_LENGTH); + hapSigningBlock.capacity() - ZIP_HEAD_OF_SIGNING_BLOCK_LENGTH); byte[] signatureValueBytes = new byte[value.capacity()]; value.get(signatureValueBytes, 0, signatureValueBytes.length); @@ -301,8 +370,8 @@ public class VerifyHap { blockLength = value.getInt(); blockType = value.getInt(); if (blockOffset + blockLength > signatureValueBytes.length) { - throw new SignatureNotFoundException("block end pos: " + (blockOffset + blockLength) + - " is larger than block len: " + signatureValueBytes.length); + throw new SignatureNotFoundException("block end pos: " + (blockOffset + blockLength) + + " is larger than block len: " + signatureValueBytes.length); } if (HapUtils.getHapSignatureOptionalBlockIds().contains(blockType)) { byte[] blockValue = Arrays.copyOfRange(signatureValueBytes, blockOffset, blockOffset + blockLength); diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/verify/VerifyResult.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/verify/VerifyResult.java index 484a23c6eb9f463ba89886f394c4ee4bbb55697e..0ad0ec25fdbcb5ada91afa9deda5432b83ce5cbb 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/verify/VerifyResult.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/hap/verify/VerifyResult.java @@ -16,6 +16,7 @@ package com.ohos.hapsigntool.hap.verify; import com.ohos.hapsigntool.hap.entity.SigningBlock; + import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cms.SignerInformation; import org.bouncycastle.util.Store; @@ -90,7 +91,17 @@ public class VerifyResult { */ public static final int RET_CRL_ERROR = 10011; - private boolean result; + /** + * Return code of file code sign data error. + */ + public static final int RET_CODESIGN_DATA_ERROR = 10012; + + /** + * Return code of verify code sign error. + */ + public static final int RET_CODE_SIGN_BLOCK_ERROR = 10013; + + private boolean isResult; private int code; private String message; @@ -115,22 +126,22 @@ public class VerifyResult { /** * Verify result constructor * - * @param result verify result + * @param isResult verify result * @param code error code * @param message error message */ - public VerifyResult(boolean result, int code, String message) { - this.result = result; + public VerifyResult(boolean isResult, int code, String message) { + this.isResult = isResult; this.code = code; this.message = message; } public boolean isVerified() { - return result; + return isResult; } - public void setResult(boolean result) { - this.result = result; + public void setIsResult(boolean isResult) { + this.isResult = isResult; } public int getCode() { diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/utils/FileUtils.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/utils/FileUtils.java index cc8d917f487594fcac05e88c72c3d915ebec73bd..fdb240afa7961e4a24b4172a1f809e121f65c576 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/utils/FileUtils.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/utils/FileUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -221,10 +221,13 @@ public final class FileUtils { * @return true, if write successfully. */ public static boolean writeByteToDos(byte[] data, DataOutputStream dos) { + if (data == null) { + return true; + } try { dos.write(data); } catch (IOException e) { - LOGGER.error("Faile to write data to output stream."); + LOGGER.error("Failed to write data to output stream."); return false; } return true; diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/utils/HapUtils.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/utils/HapUtils.java index e51a3f59505ded067c6a171757b0e1966c9843db..172f8a75789ce473b2aa459476b2d4cef5f80169 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/utils/HapUtils.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/utils/HapUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -38,12 +38,12 @@ import java.nio.ByteOrder; import java.security.DigestException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.Collections; /** * Hap util, parse hap, find signature block. @@ -73,6 +73,11 @@ public class HapUtils { */ public static final int HAP_PROPERTY_BLOCK_ID = 0x20000003; + /** + * ID of property block + */ + public static final int HAP_CODE_SIGN_BLOCK_ID = 0x30000001; + /** * The size of data block used to get digest */ @@ -97,12 +102,12 @@ public class HapUtils { /** * int size */ - public static final int INT_SIZE = 4; + public static final int INT_SIZE = 4; /** * block number */ - public static final int BLOCK_NUMBER = 1; + public static final int BLOCK_NUMBER = 1; /** * hap sign schema v2 signature block version @@ -124,55 +129,67 @@ public class HapUtils { */ public static final long HAP_SIG_BLOCK_MAGIC_HI_V2 = 0x3234206b636f6c42L; - private HapUtils() { - } - /** - * The set of IDs of optional blocks in hap signature block. + * The value of lower 8 bytes of magic word */ - private static final Set HAP_SIGNATURE_OPTIONAL_BLOCK_IDS ; + public static final long HAP_SIG_BLOCK_MAGIC_LO_V3 = 0x676973207061683cL; /** - * Minimum api version for hap sign schema v3. + * The value of higher 8 bytes of magic word */ - private static final int MIN_COMPATIBLE_VERSION_FOR_SCHEMA_V3 = 8; + public static final long HAP_SIG_BLOCK_MAGIC_HI_V3 = 0x3e6b636f6c62206eL; /** - * Magic word of hap signature block v2 + * Size of hap signature block header */ - private static final byte[] HAP_SIGNING_BLOCK_MAGIC_V2 = - new byte[] {0x48, 0x41, 0x50, 0x20, 0x53, 0x69, 0x67, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x34, 0x32}; + public static final int HAP_SIG_BLOCK_HEADER_SIZE = 32; /** - * Magic word of hap signature block + * The min size of hap signature block */ - private static final byte[] HAP_SIGNING_BLOCK_MAGIC_V3 = - new byte[] {0x3c, 0x68, 0x61, 0x70, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3e}; + public static final int HAP_SIG_BLOCK_MIN_SIZE = HAP_SIG_BLOCK_HEADER_SIZE; /** - * The value of lower 8 bytes of magic word + * The set of IDs of optional blocks in hap signature block. */ - public static final long HAP_SIG_BLOCK_MAGIC_LO_V3 = 0x676973207061683cL; + private static final Set HAP_SIGNATURE_OPTIONAL_BLOCK_IDS ; /** - * The value of higher 8 bytes of magic word + * Minimum api version for hap sign schema v3. */ - public static final long HAP_SIG_BLOCK_MAGIC_HI_V3 = 0x3e6b636f6c62206eL; + private static final int MIN_COMPATIBLE_VERSION_FOR_SCHEMA_V3 = 8; /** - * Size of hap signature block header + * Magic word of hap signature block v2 */ - public static final int HAP_SIG_BLOCK_HEADER_SIZE = 32; + private static final byte[] HAP_SIGNING_BLOCK_MAGIC_V2 = + new byte[] {0x48, 0x41, 0x50, 0x20, 0x53, 0x69, 0x67, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x20, 0x34, 0x32}; /** - * The min size of hap signature block + * Magic word of hap signature block */ - public static final int HAP_SIG_BLOCK_MIN_SIZE = HAP_SIG_BLOCK_HEADER_SIZE; + private static final byte[] HAP_SIGNING_BLOCK_MAGIC_V3 = + new byte[] {0x3c, 0x68, 0x61, 0x70, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x3e}; private static final byte ZIP_FIRST_LEVEL_CHUNK_PREFIX = 0x5a; private static final byte ZIP_SECOND_LEVEL_CHUNK_PREFIX = (byte) 0xa5; private static final int DIGEST_PRIFIX_LENGTH = 5; private static final int BUFFER_LENGTH = 4096; + private static final char[] HEX_CHAR_ARRAY = "0123456789ABCDEF".toCharArray(); + + /** + * The set of IDs of optional blocks in hap signature block. + */ + static { + Set blockIds = new HashSet(); + blockIds.add(HAP_PROOF_OF_ROTATION_BLOCK_ID); + blockIds.add(HAP_PROFILE_BLOCK_ID); + blockIds.add(HAP_PROPERTY_BLOCK_ID); + HAP_SIGNATURE_OPTIONAL_BLOCK_IDS = Collections.unmodifiableSet(blockIds); + } + + private HapUtils() { + } /** * Get HAP_SIGNATURE_OPTIONAL_BLOCK_IDS @@ -209,17 +226,6 @@ public class HapUtils { return HAP_SIGN_SCHEME_V2_BLOCK_VERSION; } - /** - * The set of IDs of optional blocks in hap signature block. - */ - static { - Set blockIds = new HashSet(); - blockIds.add(HAP_PROOF_OF_ROTATION_BLOCK_ID); - blockIds.add(HAP_PROFILE_BLOCK_ID); - blockIds.add(HAP_PROPERTY_BLOCK_ID); - HAP_SIGNATURE_OPTIONAL_BLOCK_IDS = Collections.unmodifiableSet(blockIds); - } - /** * Read data from hap file. * @@ -229,7 +235,7 @@ public class HapUtils { */ public static byte[] readFileToByte(String file) throws IOException { try (FileInputStream in = new FileInputStream(file); - ByteArrayOutputStream out = new ByteArrayOutputStream(in.available());) { + ByteArrayOutputStream out = new ByteArrayOutputStream(in.available());) { byte[] buf = new byte[BUFFER_LENGTH]; int len = 0; while ((len = in.read(buf)) != -1) { @@ -242,8 +248,8 @@ public class HapUtils { private static long getChunkCount(ZipDataInput[] contents) { long chunkCount = 0L; for (ZipDataInput content : contents) { - chunkCount += ((content.size() + CONTENT_DIGESTED_CHUNK_MAX_SIZE_BYTES - 1) / - CONTENT_DIGESTED_CHUNK_MAX_SIZE_BYTES); + chunkCount += ((content.size() + CONTENT_DIGESTED_CHUNK_MAX_SIZE_BYTES - 1) + / CONTENT_DIGESTED_CHUNK_MAX_SIZE_BYTES); } return chunkCount; } @@ -267,7 +273,7 @@ public class HapUtils { } int chunkCount = (int) chunkCountLong; ContentDigestAlgorithm[] contentDigestAlgorithms = digestAlgorithms.toArray( - new ContentDigestAlgorithm[digestAlgorithms.size()]); + new ContentDigestAlgorithm[digestAlgorithms.size()]); MessageDigest[] messageDigests = new MessageDigest[contentDigestAlgorithms.length]; int[] digestOutputSizes = new int[contentDigestAlgorithms.length]; byte[][] digestOfChunks = new byte[contentDigestAlgorithms.length][]; @@ -306,7 +312,7 @@ public class HapUtils { for (int i = 0; i < contentDigestAlgorithms.length; i++) { int expectedDigestSizeBytes = digestOutputSizes[i]; int actualDigestSizeBytes = messageDigests[i].digest(digestOfChunks[i], - chunkIndex * expectedDigestSizeBytes + DIGEST_PRIFIX_LENGTH, expectedDigestSizeBytes); + chunkIndex * expectedDigestSizeBytes + DIGEST_PRIFIX_LENGTH, expectedDigestSizeBytes); if (actualDigestSizeBytes != expectedDigestSizeBytes) { throw new DigestException("Unexpected output size of " + messageDigests[i].getAlgorithm() + " digest: " + actualDigestSizeBytes); @@ -334,7 +340,7 @@ public class HapUtils { } private static Map getContentDigestAlgorithmMap(List optionalBlocks, - ContentDigestAlgorithm[] contentDigestAlgorithms, MessageDigest[] messageDigests, byte[][] digestOfChunks) { + ContentDigestAlgorithm[] contentDigestAlgorithms, MessageDigest[] messageDigests, byte[][] digestOfChunks) { Map result = new HashMap<>(contentDigestAlgorithms.length); for (int i = 0; i < contentDigestAlgorithms.length; i++) { messageDigests[i].update(digestOfChunks[i]); @@ -352,8 +358,6 @@ public class HapUtils { } } - private static final char[] HEX_CHAR_ARRAY = "0123456789ABCDEF".toCharArray(); - /** * Slice buffer to target size. * @@ -384,7 +388,7 @@ public class HapUtils { int capacity = source.capacity(); if (startPos < 0 || endPos < startPos || endPos > capacity) { throw new IllegalArgumentException( - "startPos: " + startPos + ", endPos: " + endPos + ", capacity: " + capacity); + "startPos: " + startPos + ", endPos: " + endPos + ", capacity: " + capacity); } int limit = source.limit(); int position = source.position(); @@ -438,7 +442,7 @@ public class HapUtils { int encodeSize = 0; encodeSize += INT_SIZE + INT_SIZE; for (Pair pair : pairList) { - encodeSize += INT_SIZE+INT_SIZE+INT_SIZE + pair.getSecond().length; + encodeSize += INT_SIZE + INT_SIZE + INT_SIZE + pair.getSecond().length; } ByteBuffer encodeBytes = ByteBuffer.allocate(encodeSize); encodeBytes.order(ByteOrder.LITTLE_ENDIAN); @@ -446,7 +450,7 @@ public class HapUtils { encodeBytes.putInt(BLOCK_NUMBER); // block number for (Pair pair : pairList) { byte[] second = pair.getSecond(); - encodeBytes.putInt(INT_SIZE+INT_SIZE + second.length); + encodeBytes.putInt(INT_SIZE + INT_SIZE + second.length); encodeBytes.putInt(pair.getFirst()); encodeBytes.putInt(second.length); encodeBytes.put(second); @@ -507,11 +511,21 @@ public class HapUtils { long hapSignBlockMagicLo = hapSigningBlockHeader.getLong(); long hapSignBlockMagicHi = hapSigningBlockHeader.getLong(); int version = hapSigningBlockHeader.getInt(); + long hapSigningBlockOffset = verifySignBlock(hapSigBlockSize, + hapSignBlockMagicLo, hapSignBlockMagicHi, version, centralDirectoryStartOffset); + ByteBuffer hapSigningBlockByteBuffer = hap.createByteBuffer(hapSigningBlockOffset, (int) hapSigBlockSize) + .order(ByteOrder.LITTLE_ENDIAN); + LOGGER.info("Find Hap Signing Block success, version: {}, block count: {}", version, blockCount); + return new HapSignBlockInfo(hapSigningBlockOffset, version, hapSigningBlockByteBuffer); + } + + private static long verifySignBlock(long hapSigBlockSize, long hapSignBlockMagicLo, + long hapSignBlockMagicHi, int version, long centralDirectoryStartOffset) throws SignatureNotFoundException { if (!isVersionAndMagicNumValid(version, hapSignBlockMagicLo, hapSignBlockMagicHi)) { throw new SignatureNotFoundException("No Hap Signing Block before ZIP Central Directory"); } - if ((hapSigBlockSize < HAP_SIG_BLOCK_HEADER_SIZE) || - (hapSigBlockSize > Integer.MAX_VALUE - SignHap.getBlockSize())) { + if ((hapSigBlockSize < HAP_SIG_BLOCK_HEADER_SIZE) + || (hapSigBlockSize > Integer.MAX_VALUE - SignHap.getBlockSize())) { throw new SignatureNotFoundException("Hap Signing Block size out of range: " + hapSigBlockSize); } int totalSize = (int) hapSigBlockSize; @@ -519,10 +533,7 @@ public class HapUtils { if (hapSigningBlockOffset < 0) { throw new SignatureNotFoundException("Hap Signing Block offset out of range: " + hapSigningBlockOffset); } - ByteBuffer hapSigningBlockByteBuffer = hap.createByteBuffer(hapSigningBlockOffset, totalSize) - .order(ByteOrder.LITTLE_ENDIAN); - LOGGER.info("Find Hap Signing Block success, version: {}, block count: {}", version, blockCount); - return new HapSignBlockInfo(hapSigningBlockOffset, version, hapSigningBlockByteBuffer); + return hapSigningBlockOffset; } private static boolean isVersionAndMagicNumValid(int version, long hapSignBlockMagicLo, long hapSignBlockMagicHi) { diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/utils/ParamConstants.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/utils/ParamConstants.java index 3b1dbde6f783da007716b57a82f6bc557d008fa6..bb6ff785d0e99461281394a00f61992a735ec8ad 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/utils/ParamConstants.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/utils/ParamConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -236,12 +236,27 @@ public class ParamConstants { */ public static final String PARAM_RESIGN_CONFIG_FILE = "resignconfig"; + /** + * sign file type bin or zip or elf + */ + public static final String PARAM_IN_FORM = "inForm"; + + /** + * The code sign params of resign hap + */ + public static final String PARAM_SIGN_CODE = "signcode"; + + /** + * file name split . of min length + */ + public static final int FILE_NAME_MIN_LENGTH = 2; + /** * Enumerated value of whether a profile is signed */ public enum ProfileSignFlag { - UNSIGNED_PROFILE("0"), - SIGNED_PROFILE("1"); + DISABLE_SIGN_CODE("0"), + ENABLE_SIGN_CODE("1"); private String signFlag; @@ -253,4 +268,22 @@ public class ParamConstants { return signFlag; } } + + /** + * Enumerated value of whether a code sign is signed. + */ + public enum SignCodeFlag { + DISABLE_SIGN_CODE("0"), + ENABLE_SIGN_CODE("1"); + + private String signCodeFlag; + + SignCodeFlag(String signCodeFlag) { + this.signCodeFlag = signCodeFlag; + } + + public String getSignCodeFlag() { + return signCodeFlag; + } + } } \ No newline at end of file diff --git a/tools/commands.config b/tools/commands.config index 559d8c1c93c508bd9a1bb432dad4127d1eac8096..11ee56b64c5a39896c4b1f938404600aabce5fcc 100644 --- a/tools/commands.config +++ b/tools/commands.config @@ -85,11 +85,22 @@ 'verify-profile -inFile "app1-profile1.p7b"', 'verify-profile -inFile "app1-profile1.p7b" -outFile', 'verify-profile -inFile "app1-profile-cert-outTime.p7b" -outFile "result.json"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app2.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_nopass.jks" -outFile "app1-signed.hap" -inForm "zip" -profileSigned "1" -extCfgFile "111.txt"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "profile.json" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456" -inForm "bin" ', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456" -inForm "bin"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "profile.json" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "0"' + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app2.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_nopass.jks" -outFile "app1-signedcode.hap" -inForm "zip" -profileSigned "1" -extCfgFile "111.txt"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app2.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_nopass.jks" -outFile "app1-unsignedcode.hap" -inForm "zip" -profileSigned "1" -extCfgFile "111.txt" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app2.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_nopass.jks" -outFile "app1-signedcode.hap" -inForm "zip" -profileSigned "1" -extCfgFile "111.txt" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "profile.json" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -inForm "bin" ', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "profile.json" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -inForm "bin" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "profile.json" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -inForm "bin" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -inForm "bin"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -inForm "bin" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -inForm "bin" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "profile.json" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "profile.json" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "0" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "profile.json" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "0" -signcode "1"', + 'verify-app -inFile "app1-signedcode.hap" -outCertChain "app-sign-srv-ca1.cer" -outProfile "app1-profile.p7b"' ], 'case-assert-false': [ 'generate-keypair -keyPwd 123456 -keyAlg ECC -keySize NIST-P-384 -keystoreFile "ohtest.jks" -keystorePwd 123456 -extCfgFile "111.txt"', @@ -339,45 +350,125 @@ 'verify-profile -outFile "verify-result.json" -inFile "app1-profile1.jks"', 'verify-profile -inFile "app1-profile1-changed.p7b" -outFile "verify-result.json"', 'verify-profile -inFile "app1-profile1.p7b" -outFile "verify-result.js00on"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "remoteSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "rewrw@%$" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1-222" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456789" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile1-changed.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "profile.json" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "1"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "0"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "5"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "String"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "notexist\test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "profile.json" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "HMAC" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withRSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v2" -signAlg "SHA256withRSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v2" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohnull.p12" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.txt" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app2.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_nopass.jks" -outFile "app1-signed.hap" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456789"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signed.hap" -keyPwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "remoteSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "remoteSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "remoteSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "rewrw@%$" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "rewrw@%$" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "rewrw@%$" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1-222" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1-222" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1-222" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456789" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456789" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456789" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile1-changed.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile1-changed.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile1-changed.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "profile.json" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "profile.json" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "1" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "profile.json" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "1" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "0" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "0" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "5"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "5" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "5" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "String"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "String" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -profileSigned "String" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "notexist\test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "notexist\test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "notexist\test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "profile.json" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "profile.json" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "profile.json" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "HMAC" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "HMAC" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "HMAC" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withRSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withRSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withRSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v2" -signAlg "SHA256withRSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v2" -signAlg "SHA256withRSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v2" -signAlg "SHA256withRSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v2" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v2" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v2" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohnull.p12" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohnull.p12" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohnull.p12" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.txt" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.txt" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.txt" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app2.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_nopass.jks" -outFile "app1-signedcode.hap" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app2.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_nopass.jks" -outFile "app1-unsignedcode.hap" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app2.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_nopass.jks" -outFile "app1-signedcode.hap" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456789"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456789" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456789" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -signcode "1"', 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_pass.jks" -outFile -keyPwd "123456" -keystorePwd "123456" -signcode "1"', 'sign-profile -keyAlias "oh-profile1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -profileCertFile "profile1_error.pem" -inFile "app1-profile-release.json" -keystoreFile "ohtest_pass.jks" -outFile "app1-profile.p7b" -keyPwd "123456" -keystorePwd "123456"', 'sign-profile -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -profileCertFile "profile1.pem" -inFile "app1-profile-release.json" -keystoreFile "ohtest.jks" -outFile "app1-profile.p7b" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1_error.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-profile1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest.jks" -outFile "app1-signed.hap" -keyPwd "123456" -keystorePwd "123456"', - 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app2.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_nopass.jks" -outFile "app1-signed.hap" -inForm -profileSigned -extCfgFile ', - 'sign-app -keyAlias "oh-app1-key-v1" -keyPwd "123456" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app2.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_nopass.jks" -outFile "app1-signed.hap" -inForm -profileSigned -extCfgFile ' + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1_error.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1_error.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1_error.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-profile1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456"', + 'sign-app -keyAlias "oh-profile1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest.jks" -outFile "app1-unsignedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "0"', + 'sign-app -keyAlias "oh-profile1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app1.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest.jks" -outFile "app1-signedcode.hap" -keyPwd "123456" -keystorePwd "123456" -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app2.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_nopass.jks" -outFile "app1-signedcode.hap" -inForm -profileSigned -extCfgFile ', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app2.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_nopass.jks" -outFile "app1-unsignedcode.hap" -inForm -profileSigned -extCfgFile -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app2.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_nopass.jks" -outFile "app1-signedcode.hap" -inForm -profileSigned -extCfgFile -signcode "1"', + 'sign-app -keyAlias "oh-app1-key-v1" -keyPwd "123456" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app2.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_nopass.jks" -outFile "app1-signedcode.hap" -inForm -profileSigned -extCfgFile ', + 'sign-app -keyAlias "oh-app1-key-v1" -keyPwd "123456" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app2.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_nopass.jks" -outFile "app1-unsignedcode.hap" -inForm -profileSigned -extCfgFile -signcode "0"', + 'sign-app -keyAlias "oh-app1-key-v1" -keyPwd "123456" -signAlg "SHA256withECDSA" -mode "localSign" -appCertFile "app2.pem" -profileFile "app1-profile.p7b" -inFile "test/app1-unsigned.hap" -keystoreFile "ohtest_nopass.jks" -outFile "app1-signedcode.hap" -inForm -profileSigned -extCfgFile -signcode "1"', + 'verify-app -inFile "app1-signedcode.hap" -outCertChain "" -outProfile "app1-profile.p7b"', + 'verify-app -inFile "app1-signedcode.hap" -outCertChain "app1.cer" -outProfile ""', + 'verify-app -inFile "app1-signedcode.hap" -outCertChain "" -outProfile ""', + 'verify-app -inFile "app1-signedcode.hap" -outCertChain "app1.ce7778r" -outProfile "app1-profile1.p7b"', ] } \ No newline at end of file